diff --git a/.env.testing.example b/.env.testing.example index 6f91497b..62c677a5 100644 --- a/.env.testing.example +++ b/.env.testing.example @@ -9,4 +9,6 @@ DEV_LIVE_SERVER_UNIT_TEST_CHANNEL=UnitTest DEV_LIVE_SERVER_UNIT_TEST_USER_ACTIVE=false DEV_LIVE_SERVER_UNIT_TEST_USER=UnitTestUser DEV_LIVE_SERVER_UNIT_TEST_SIGNALS=false -DEV_LIVE_SERVER_UNIT_TEST_USER_EXTEND= +DEV_LIVE_SERVER_UNIT_TEST_USER_EXTEND=UnitTestUser2 +DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=9987 +DEV_LIVE_SERVER_UNIT_TEST_SERVER_QUERY_LOGIN_NAME=ts3-bot-dev diff --git a/composer.lock b/composer.lock index 3dddff5f..fd3cbc70 100644 --- a/composer.lock +++ b/composer.lock @@ -127,16 +127,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.52", + "version": "3.0.55", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce" + "reference": "db9744e6d47e742b1f974e965ad49bdd041105af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2adaefc83df2ec548558307690f376dd7d4f4fce", - "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/db9744e6d47e742b1f974e965ad49bdd041105af", + "reference": "db9744e6d47e742b1f974e965ad49bdd041105af", "shasum": "" }, "require": { @@ -217,7 +217,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.52" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.55" }, "funding": [ { @@ -233,7 +233,7 @@ "type": "tidelift" } ], - "time": "2026-04-27T07:02:15+00:00" + "time": "2026-06-14T23:24:10+00:00" } ], "packages-dev": [ @@ -303,28 +303,29 @@ }, { "name": "composer/pcre", - "version": "3.3.2", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed", + "reference": "d5a341b3fb61f3001970940afb1d332968a183ed", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, "conflict": { - "phpstan/phpstan": "<1.11.10" + "phpstan/phpstan": "<2.2.2" }, "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^9" }, "type": "library", "extra": { @@ -362,7 +363,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" + "source": "https://github.com/composer/pcre/tree/3.4.0" }, "funding": [ { @@ -372,13 +373,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2024-11-12T16:29:46+00:00" + "time": "2026-06-07T11:47:49+00:00" }, { "name": "composer/semver", @@ -702,16 +699,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.95.5", + "version": "v3.95.17", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7f86d8763063f5d2e2e2d0e1e45bb2f15895361d" + "reference": "0ee88422118f3cc59c8c3def222ba7f1493b6d5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7f86d8763063f5d2e2e2d0e1e45bb2f15895361d", - "reference": "7f86d8763063f5d2e2e2d0e1e45bb2f15895361d", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/0ee88422118f3cc59c8c3def222ba7f1493b6d5b", + "reference": "0ee88422118f3cc59c8c3def222ba7f1493b6d5b", "shasum": "" }, "require": { @@ -745,16 +742,16 @@ "require-dev": { "facile-it/paraunit": "^1.3.1 || ^2.11.0", "infection/infection": "^0.32.7", - "justinrainbow/json-schema": "^6.8.0", + "justinrainbow/json-schema": "^6.10.0", "keradus/cli-executor": "^2.3", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.9.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.8", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.8", - "phpunit/phpunit": "^9.6.34 || ^10.5.63 || ^11.5.55", - "symfony/polyfill-php85": "^1.37", - "symfony/var-dumper": "^5.4.48 || ^6.4.32 || ^7.4.4 || ^8.0.8", - "symfony/yaml": "^5.4.45 || ^6.4.30 || ^7.4.1 || ^8.0.11" + "phpunit/phpunit": "^9.6.35 || ^10.5.64 || ^11.5.56 || ^12.5.31 || ^13.0.6", + "symfony/polyfill-php85": "^1.38", + "symfony/var-dumper": "^5.4.48 || ^6.4.36 || ^7.4.8 || ^8.1.1", + "symfony/yaml": "^5.4.53 || ^6.4.41 || ^7.4.13 || ^8.1.1" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -795,7 +792,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.5" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.95.17" }, "funding": [ { @@ -803,7 +800,7 @@ "type": "github" } ], - "time": "2026-06-09T14:55:16+00:00" + "time": "2026-07-24T13:54:39+00:00" }, { "name": "myclabs/deep-copy", @@ -867,20 +864,19 @@ }, { "name": "nikic/php-parser", - "version": "v5.7.0", + "version": "v5.8.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", - "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f", + "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f", "shasum": "" }, "require": { - "ext-ctype": "*", "ext-json": "*", "ext-tokenizer": "*", "php": ">=7.4" @@ -919,9 +915,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0" }, - "time": "2025-12-06T11:56:16+00:00" + "time": "2026-07-04T14:30:18+00:00" }, { "name": "phar-io/manifest", @@ -1388,24 +1384,24 @@ }, { "name": "phpunit/phpunit", - "version": "12.5.29", + "version": "12.5.33", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9aa66a47db3ea70f1a468e66dd969f67e594945a" + "reference": "b98e028a26c5c5ba7e4a54be96ccf35f2914d184" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9aa66a47db3ea70f1a468e66dd969f67e594945a", - "reference": "9aa66a47db3ea70f1a468e66dd969f67e594945a", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b98e028a26c5c5ba7e4a54be96ccf35f2914d184", + "reference": "b98e028a26c5c5ba7e4a54be96ccf35f2914d184", "shasum": "" }, "require": { "ext-dom": "*", + "ext-filter": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-xml": "*", "ext-xmlwriter": "*", "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", @@ -1466,7 +1462,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.29" + "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.33" }, "funding": [ { @@ -1474,7 +1470,7 @@ "type": "other" } ], - "time": "2026-06-04T06:14:42+00:00" + "time": "2026-07-28T13:58:09+00:00" }, { "name": "psr/container", @@ -3118,16 +3114,16 @@ }, { "name": "symfony/console", - "version": "v7.4.13", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "85095d2573eaefaf35e40b9513a9bf09f72cd217" + "reference": "088ec6fe0ef6819cbc301174093b6bfa4ad26930" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/85095d2573eaefaf35e40b9513a9bf09f72cd217", - "reference": "85095d2573eaefaf35e40b9513a9bf09f72cd217", + "url": "https://api.github.com/repos/symfony/console/zipball/088ec6fe0ef6819cbc301174093b6bfa4ad26930", + "reference": "088ec6fe0ef6819cbc301174093b6bfa4ad26930", "shasum": "" }, "require": { @@ -3192,7 +3188,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.4.13" + "source": "https://github.com/symfony/console/tree/v7.4.15" }, "funding": [ { @@ -3212,20 +3208,20 @@ "type": "tidelift" } ], - "time": "2026-05-24T08:56:14+00:00" + "time": "2026-07-27T13:51:00+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -3263,7 +3259,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -3283,20 +3279,20 @@ "type": "tidelift" } ], - "time": "2026-04-13T15:52:40+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.4.9", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101" + "reference": "336e7f3b9e95aba04f93ea9143920c2186abfbb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/e4a2e29753c7801f7a8340e066cfa788f3bc8101", - "reference": "e4a2e29753c7801f7a8340e066cfa788f3bc8101", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/336e7f3b9e95aba04f93ea9143920c2186abfbb9", + "reference": "336e7f3b9e95aba04f93ea9143920c2186abfbb9", "shasum": "" }, "require": { @@ -3348,7 +3344,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.9" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.15" }, "funding": [ { @@ -3368,20 +3364,20 @@ "type": "tidelift" } ], - "time": "2026-04-18T13:18:21+00:00" + "time": "2026-07-21T15:13:06+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32" + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/ccba7060602b7fed0b03c85bf025257f76d9ef32", - "reference": "ccba7060602b7fed0b03c85bf025257f76d9ef32", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/c7de7a00ffb67842132da02ea92988a39ccd9f4e", + "reference": "c7de7a00ffb67842132da02ea92988a39ccd9f4e", "shasum": "" }, "require": { @@ -3428,7 +3424,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.7.1" }, "funding": [ { @@ -3448,20 +3444,20 @@ "type": "tidelift" } ], - "time": "2026-01-05T13:30:16+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/filesystem", - "version": "v7.4.11", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "d721ea61b4a5fba8c5b6e7c1feda19efea144b50" + "reference": "ff16a16bf87fdf264638b8f6995b3515975e3c79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/d721ea61b4a5fba8c5b6e7c1feda19efea144b50", - "reference": "d721ea61b4a5fba8c5b6e7c1feda19efea144b50", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/ff16a16bf87fdf264638b8f6995b3515975e3c79", + "reference": "ff16a16bf87fdf264638b8f6995b3515975e3c79", "shasum": "" }, "require": { @@ -3498,7 +3494,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.4.11" + "source": "https://github.com/symfony/filesystem/tree/v7.4.15" }, "funding": [ { @@ -3518,20 +3514,20 @@ "type": "tidelift" } ], - "time": "2026-05-11T16:38:44+00:00" + "time": "2026-07-22T07:36:05+00:00" }, { "name": "symfony/finder", - "version": "v7.4.8", + "version": "v7.4.14", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "e0be088d22278583a82da281886e8c3592fbf149" + "reference": "13b38720174286f55d1761152b575a8d1436fc25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/e0be088d22278583a82da281886e8c3592fbf149", - "reference": "e0be088d22278583a82da281886e8c3592fbf149", + "url": "https://api.github.com/repos/symfony/finder/zipball/13b38720174286f55d1761152b575a8d1436fc25", + "reference": "13b38720174286f55d1761152b575a8d1436fc25", "shasum": "" }, "require": { @@ -3566,7 +3562,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.4.8" + "source": "https://github.com/symfony/finder/tree/v7.4.14" }, "funding": [ { @@ -3586,7 +3582,7 @@ "type": "tidelift" } ], - "time": "2026-03-24T13:12:05+00:00" + "time": "2026-06-27T08:31:18+00:00" }, { "name": "symfony/options-resolver", @@ -3744,16 +3740,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.38.1", + "version": "v1.41.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "e9247d281d694a5120554d9afaf54e070e88a603" + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603", - "reference": "e9247d281d694a5120554d9afaf54e070e88a603", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", + "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d", "shasum": "" }, "require": { @@ -3802,7 +3798,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0" }, "funding": [ { @@ -3822,7 +3818,7 @@ "type": "tidelift" } ], - "time": "2026-05-26T05:58:03+00:00" + "time": "2026-07-28T08:25:59+00:00" }, { "name": "symfony/polyfill-intl-normalizer", @@ -4305,16 +4301,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { @@ -4368,7 +4364,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -4388,7 +4384,7 @@ "type": "tidelift" } ], - "time": "2026-03-28T09:44:51+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { "name": "symfony/stopwatch", @@ -4458,16 +4454,16 @@ }, { "name": "symfony/string", - "version": "v7.4.13", + "version": "v7.4.15", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde" + "reference": "e394af32256bf9e7bf80849d95e589167c10097b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", - "reference": "961683010db3b27ec6ebcd7308e6e1ee8fa7ffde", + "url": "https://api.github.com/repos/symfony/string/zipball/e394af32256bf9e7bf80849d95e589167c10097b", + "reference": "e394af32256bf9e7bf80849d95e589167c10097b", "shasum": "" }, "require": { @@ -4525,7 +4521,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.4.13" + "source": "https://github.com/symfony/string/tree/v7.4.15" }, "funding": [ { @@ -4545,7 +4541,7 @@ "type": "tidelift" } ], - "time": "2026-05-23T15:23:29+00:00" + "time": "2026-07-28T07:33:02+00:00" }, { "name": "theseer/tokenizer", diff --git a/doc/coverage/coverage-badge.svg b/doc/coverage/coverage-badge.svg index eeca55cb..e7746bf0 100644 --- a/doc/coverage/coverage-badge.svg +++ b/doc/coverage/coverage-badge.svg @@ -14,6 +14,6 @@ coverage - 65% + 69% \ No newline at end of file diff --git a/src/Adapter/FileTransfer.php b/src/Adapter/FileTransfer.php index 89941041..97f9aa69 100644 --- a/src/Adapter/FileTransfer.php +++ b/src/Adapter/FileTransfer.php @@ -7,6 +7,7 @@ use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Profiler; use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Signal; use PlanetTeamSpeak\TeamSpeak3Framework\Helper\StringHelper; +use PlanetTeamSpeak\TeamSpeak3Framework\Transport\TCP; use PlanetTeamSpeak\TeamSpeak3Framework\Transport\Transport; /** @@ -21,7 +22,7 @@ class FileTransfer extends Adapter */ public function syn(): void { - $this->initTransport($this->options); + $this->initTransport($this->options, TCP::class); $this->transport->setAdapter($this); Profiler::init(spl_object_hash($this)); @@ -42,14 +43,14 @@ public function __destruct() /** * Sends a valid file transfer key to the server to initialize the file transfer. * - * @param string $ftkey + * @param string $ftkey * @return void * @throws FileTransferException * @throws TransportException */ protected function init(string $ftkey): void { - if (strlen($ftkey) != 32 && strlen($ftkey) != 16) { + if (strlen($ftkey) !== 32 && strlen($ftkey) !== 16) { throw new FileTransferException('invalid file transfer key format'); } @@ -62,9 +63,9 @@ protected function init(string $ftkey): void /** * Sends the content of a file to the server. * - * @param string $ftkey - * @param int $seek - * @param string $data + * @param string $ftkey + * @param int $seek + * @param string $data * @return void * @throws FileTransferException * @throws TransportException @@ -78,14 +79,15 @@ public function upload(string $ftkey, int $seek, string $data): void Signal::getInstance()->emit('filetransferUploadStarted', $ftkey, $seek, $size); - for (; $seek < $size;) { + while ($seek < $size) { $rest = $size - $seek; - $pack = min($rest, $pack); - $buff = substr($data, $seek, $pack); - $seek = $seek + $pack; + $chunkSize = min($rest, $pack); + $buff = substr($data, $seek, $chunkSize); $this->getTransport()->send($buff); + $seek += $chunkSize; + Signal::getInstance()->emit('filetransferUploadProgress', $ftkey, $seek, $size); } @@ -97,9 +99,9 @@ public function upload(string $ftkey, int $seek, string $data): void /** * Returns the content of a downloaded file as a PlanetTeamSpeak\TeamSpeak3Framework\Helper\StringHelper object. * - * @param string $ftkey - * @param int $size - * @param bool $passthru + * @param string $ftkey + * @param int $size + * @param bool $passthru * @return StringHelper|void * @throws FileTransferException * @throws TransportException @@ -119,13 +121,16 @@ public function download(string $ftkey, int $size, bool $passthru = false) Signal::getInstance()->emit('filetransferDownloadStarted', $ftkey, count($buff), $size); - for ($seek = 0; $seek < $size;) { - $rest = $size - $seek; - $pack = min($rest, $pack); - $data = $this->getTransport()->read(min($rest, $pack)); - $seek = $seek + $pack; + while (count($buff) < $size) { + $rest = $size - count($buff); + $chunkSize = min($rest, $pack); + $data = $this->getTransport()->read($chunkSize); + + if (count($data) === 0) { + break; + } - $buff->append($data); + $buff->append($data->toString()); Signal::getInstance()->emit('filetransferDownloadProgress', $ftkey, count($buff), $size); } @@ -134,7 +139,7 @@ public function download(string $ftkey, int $size, bool $passthru = false) Signal::getInstance()->emit('filetransferDownloadFinished', $ftkey, count($buff), $size); - if (strlen($buff) != $size) { + if (count($buff) !== $size) { throw new FileTransferException('incomplete file download ('.count($buff).' of '.$size.' bytes)'); } @@ -151,10 +156,16 @@ public function download(string $ftkey, int $size, bool $passthru = false) */ protected function passthru(int $size): void { - $buff_size = fpassthru($this->getTransport()->getStream()); + $stream = $this->getTransport()->getStream(); + + if (! is_resource($stream)) { + throw new FileTransferException('invalid file transfer stream'); + } + + $buffSize = fpassthru($stream); - if ($buff_size != $size) { - throw new FileTransferException('incomplete file download ('.$buff_size.' of '.$size.' bytes)'); + if ($buffSize !== $size) { + throw new FileTransferException('incomplete file download ('.$buffSize.' of '.$size.' bytes)'); } } } diff --git a/src/Node/Channel.php b/src/Node/Channel.php index 179a67c3..96af37e6 100644 --- a/src/Node/Channel.php +++ b/src/Node/Channel.php @@ -332,6 +332,44 @@ public function dirCreate(string $cpw = '', string $dirname = '/'): void $this->getParent()->channelDirCreate($this->getId(), $cpw, $dirname); } + /** + * Downloads a file from this channel file repository. + * + * @param string $name + * @param string $cpw + * @param int $seekpos + * @return StringHelper + * @throws AdapterException + * @throws FileTransferException + * @throws ServerQueryException + * @throws TransportException + * @throws \Exception + */ + public function fileDownload(string $name, string $cpw = '', int $seekpos = 0): StringHelper + { + return $this->getParent()->channelFileDownload($this->getId(), $name, $cpw, $seekpos); + } + + /** + * Uploads a file into this channel file repository. + * + * @param string $name + * @param string $data + * @param string $cpw + * @param bool $overwrite + * @param bool $resume + * @return void + * @throws AdapterException + * @throws FileTransferException + * @throws ServerQueryException + * @throws TransportException + * @throws \Exception + */ + public function fileUpload(string $name, string $data, string $cpw = '', bool $overwrite = false, bool $resume = false) :void + { + $this->getParent()->channelFileUpload($this->getId(), $name, $data, $cpw, $overwrite, $resume); + } + /** * Returns the level of the channel. * @@ -417,9 +455,10 @@ public function iconDownload() } $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName('channel_icon_id')); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($download['host'], ':') ? '['.$download['host'].']' : $download['host']).':'.$download['port']); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->getParent()->buildFileTransferUri($download)); - return $transfer->download($download['ftkey'], $download['size']); + return $transfer->download($ftkey, (int) $download['size']); } /** diff --git a/src/Node/Client.php b/src/Node/Client.php index 0c577dde..4feda7ec 100644 --- a/src/Node/Client.php +++ b/src/Node/Client.php @@ -374,9 +374,10 @@ public function avatarDownload() } $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->avatarGetName()); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($download['host'], ':') ? '['.$download['host'].']' : $download['host']).':'.$download['port']); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->getParent()->buildFileTransferUri($download)); - return $transfer->download($download['ftkey'], $download['size']); + return $transfer->download($ftkey, (int) $download['size']); } /** @@ -476,9 +477,10 @@ public function iconDownload() } $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName('client_icon_id')); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($download['host'], ':') ? '['.$download['host'].']' : $download['host']).':'.$download['port']); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->getParent()->buildFileTransferUri($download)); - return $transfer->download($download['ftkey'], $download['size']); + return $transfer->download($ftkey, (int) $download['size']); } /** diff --git a/src/Node/Group.php b/src/Node/Group.php index 7bfbaa8b..ece6a7ed 100644 --- a/src/Node/Group.php +++ b/src/Node/Group.php @@ -63,9 +63,10 @@ public function iconDownload() } $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName('iconid')); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($download['host'], ':') ? '['.$download['host'].']' : $download['host']).':'.$download['port']); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->getParent()->buildFileTransferUri($download)); - return $transfer->download($download['ftkey'], $download['size']); + return $transfer->download($ftkey, (int) $download['size']); } /** diff --git a/src/Node/Server.php b/src/Node/Server.php index 6cb53417..120949ef 100644 --- a/src/Node/Server.php +++ b/src/Node/Server.php @@ -2077,6 +2077,47 @@ public function permRemoveAny(int $permid): int return count($assignments); } + /** + * Removes protocol/meta rows from a file transfer init response and returns the row containing ftkey/port. + * + * @param array $response + * @return array + * @throws ServerQueryException + */ + protected function normalizeTransferInitResponse(array $response): array + { + if (isset($response['ftkey']) || isset($response['port'])) { + return $response; + } + + foreach ($response as $row) { + if (! is_array($row)) { + continue; + } + + if (isset($row['ftkey']) || isset($row['port'])) { + return $row; + } + } + + throw new ServerQueryException('invalid file transfer init response'); + } + + /** + * Initializes a file transfer upload. $clientftfid is an arbitrary ID to identify the file transfer on the client-side. + * + * @param int $clientftfid + * @param int $cid + * @param string $name + * @param int $size + * @param string $cpw + * @param bool $overwrite + * @param bool $resume + * @return array + * @throws AdapterException + * @throws ServerQueryException + * @throws TransportException + */ /** * Initializes a file transfer upload. $clientftfid is an arbitrary ID to identify the file transfer on the client-side. * @@ -2101,21 +2142,31 @@ public function transferInitUpload( bool $overwrite = false, bool $resume = false ): array { - $upload = $this->execute('ftinitupload', ['clientftfid' => $clientftfid, 'cid' => $cid, 'name' => $name, 'cpw' => $cpw, 'size' => $size, 'overwrite' => $overwrite, 'resume' => $resume]) - ->toList(); + $response = $this->execute('ftinitupload', [ + 'clientftfid' => $clientftfid, + 'cid' => $cid, + 'name' => $name, + 'cpw' => $cpw, + 'size' => $size, + 'overwrite' => $overwrite, + 'resume' => $resume, + ])->toList(); + + $upload = $this->normalizeTransferInitResponse($response); if (array_key_exists('status', $upload) && $upload['status'] != 0x00) { - throw new ServerQueryException($upload['msg'], $upload['status']); + throw new ServerQueryException((string) $upload['msg'], (int) $upload['status']); } $upload['cid'] = $cid; $upload['file'] = $name; - if (! array_key_exists('ip', $upload) || $upload['ip']->startsWith('0.0.0.0')) { + if (! array_key_exists('ip', $upload) || (string) $upload['ip'] === '' || (string) $upload['ip'] === '0.0.0.0') { $upload['ip'] = $this->getParent()->getAdapterHost(); - } else { + } elseif ($upload['ip'] instanceof StringHelper) { $upload['ip'] = $upload['ip']->section(','); } + $upload['host'] = $upload['ip']; Signal::getInstance()->emit('filetransferUploadInit', $upload['ftkey'], $upload); @@ -2138,21 +2189,29 @@ public function transferInitUpload( */ public function transferInitDownload(int $clientftfid, int $cid, string $name, string $cpw = '', int $seekpos = 0): array { - $download = $this->execute('ftinitdownload', ['clientftfid' => $clientftfid, 'cid' => $cid, 'name' => $name, 'cpw' => $cpw, 'seekpos' => $seekpos]) - ->toList(); + $response = $this->execute('ftinitdownload', [ + 'clientftfid' => $clientftfid, + 'cid' => $cid, + 'name' => $name, + 'cpw' => $cpw, + 'seekpos' => $seekpos, + ])->toList(); + + $download = $this->normalizeTransferInitResponse($response); if (array_key_exists('status', $download) && $download['status'] != 0x00) { - throw new ServerQueryException($download['msg'], $download['status']); + throw new ServerQueryException((string) $download['msg'], (int) $download['status']); } $download['cid'] = $cid; $download['file'] = $name; - if (! array_key_exists('ip', $download) || $download['ip']->startsWith('0.0.0.0')) { + if (! array_key_exists('ip', $download) || (string) $download['ip'] === '' || (string) $download['ip'] === '0.0.0.0') { $download['ip'] = $this->getParent()->getAdapterHost(); - } else { + } elseif ($download['ip'] instanceof StringHelper) { $download['ip'] = $download['ip']->section(','); } + $download['host'] = $download['ip']; Signal::getInstance()->emit('filetransferDownloadInit', $download['ftkey'], $download); @@ -2189,6 +2248,107 @@ public function transferStop(int $serverftfid, bool $delete = false): void $this->execute('ftstop', ['serverftfid' => $serverftfid, 'delete' => $delete]); } + /** + * Builds a valid filetransfer URI from ftinitupload/ftinitdownload response data. + * + * @param array $transfer + * @return string + * @throws ServerQueryException + */ + public function buildFileTransferUri(array $transfer): string + { + $host = $transfer['host'] ?? $transfer['ip'] ?? $this->getParent()->getAdapterHost(); + $port = $transfer['port'] ?? null; + + if ($host instanceof StringHelper) { + $host = $host->toString(); + } + + if ($port instanceof StringHelper) { + $port = $port->toString(); + } + + $host = trim((string) $host); + $port = is_numeric($port) ? (int) $port : 0; + + if ($host === '' || $host === '0.0.0.0') { + $host = $this->getParent()->getAdapterHost(); + } + + if ($host instanceof StringHelper) { + $host = $host->toString(); + } + + $host = trim((string) $host); + + if ($host === '') { + throw new ServerQueryException('invalid file transfer host'); + } + + if ($port < 1 || $port > 65535) { + throw new ServerQueryException('invalid file transfer port: '.json_encode($transfer)); + } + + return 'filetransfer://'.(str_contains($host, ':') ? '['.$host.']' : $host).':'.$port; + } + + /** + * Downloads a file from a channel file repository. + * + * @param int $cid + * @param string $name + * @param string $cpw + * @param int $seekpos + * @return StringHelper + * @throws AdapterException + * @throws FileTransferException + * @throws ServerQueryException + * @throws TransportException + * @throws Exception + */ + public function channelFileDownload(int $cid, string $name, string $cpw = '', int $seekpos = 0): StringHelper + { + $download = $this->transferInitDownload(rand(0x0000, 0xFFFF), $cid, $name, $cpw, $seekpos); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->buildFileTransferUri($download)); + + return $transfer->download($ftkey, (int) $download['size']); + } + + /** + * Uploads a file into a channel file repository. + * + * @param int $cid + * @param string $name + * @param string $data + * @param string $cpw + * @param bool $overwrite + * @param bool $resume + * @return void + * @throws AdapterException + * @throws FileTransferException + * @throws ServerQueryException + * @throws TransportException + * @throws Exception + */ + public function channelFileUpload(int $cid, string $name, string $data, string $cpw = '', bool $overwrite = false, bool $resume = false): void + { + $upload = $this->transferInitUpload( + rand(0x0000, 0xFFFF), + $cid, + $name, + strlen($data), + $cpw, + $overwrite, + $resume + ); + + $ftkey = str_replace('\\/', '/', (string) $upload['ftkey']); + + $transfer = TeamSpeak3::factory($this->buildFileTransferUri($upload)); + $transfer->upload($ftkey, (int) $upload['seekpos'], $data); + } + /** * Downloads and returns the servers icon file content. * @@ -2218,35 +2378,62 @@ public function iconDownload(string $iconname = null) } $download = $this->transferInitDownload(rand(0x0000, 0xFFFF), 0, $name); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($download['host'], ':') ? '['.$download['host'].']' : $download['host']).':'.$download['port']); + $ftkey = str_replace('\\/', '/', (string) $download['ftkey']); + $transfer = TeamSpeak3::factory($this->buildFileTransferUri($download)); - return $transfer->download($download['ftkey'], $download['size']); + return $transfer->download($ftkey, (int) $download['size']); } /** * Uploads a given icon file content to the server and returns the ID of the icon. * * @param string $data + * @param bool $overwrite * @return int * @throws AdapterException * @throws FileTransferException + * @throws HelperException * @throws ServerQueryException * @throws TransportException - * @throws Exception */ - public function iconUpload(string $data): int + public function iconUpload(string $data, bool $overwrite = true): int { + if (is_file($data)) { + $data = file_get_contents($data); + + if ($data === false) { + throw new ServerQueryException('unable to read icon file'); + } + } + $crc = crc32($data); $size = strlen($data); - $upload = $this->transferInitUpload(rand(0x0000, 0xFFFF), 0, '/icon_'.$crc, $size); - $transfer = TeamSpeak3::factory('filetransfer://'.(str_contains($upload['host'], ':') ? '['.$upload['host'].']' : $upload['host']).':'.$upload['port']); + $upload = $this->transferInitUpload(rand(0x0000, 0xFFFF), 0, '/icon_'.$crc, $size, '', $overwrite); + $ftkey = str_replace('\\/', '/', (string) $upload['ftkey']); - $transfer->upload($upload['ftkey'], $upload['seekpos'], $data); + $transfer = TeamSpeak3::factory($this->buildFileTransferUri($upload)); + $transfer->upload($ftkey, (int) $upload['seekpos'], $data); return $crc; } + /** + * @throws AdapterException + * @throws ServerQueryException + * @throws TransportException + */ + public function iconDelete(string|int $icon): void + { + $name = (string) $icon; + + if (! str_starts_with($name, 'icon_')) { + $name = 'icon_'.$name; + } + + $this->channelFileDelete(0, '', '/'.$name); + } + /** * Changes the virtual server configuration using given properties. * diff --git a/src/Node/ServerGroup.php b/src/Node/ServerGroup.php index 03470aba..fdee024e 100644 --- a/src/Node/ServerGroup.php +++ b/src/Node/ServerGroup.php @@ -206,7 +206,6 @@ protected function fetchNodeList(): void */ public function getIcon(): string { - //TODO: HÄ whats this? return 'group_server'; } } diff --git a/src/Transport/TCP.php b/src/Transport/TCP.php new file mode 100644 index 00000000..fe23fcf1 --- /dev/null +++ b/src/Transport/TCP.php @@ -0,0 +1,93 @@ +stream !== null) { + return; + } + + $host = strval($this->config['host']); + $port = strval($this->config['port']); + + $address = 'tcp://'.(str_contains($host, ':') ? '['.$host.']' : $host).':'.$port; + $timeout = (int) $this->config['timeout']; + + $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); + + if ($this->stream === false) { + $this->stream = null; + + throw new TransportException(StringHelper::factory($errstr)->toUtf8()->toString(), $errno); + } + + stream_set_timeout($this->stream, $timeout); + stream_set_blocking($this->stream, $this->config['blocking'] ? 1 : 0); + } + + /** + * Disconnects from a remote server. + */ + public function disconnect(): void + { + if ($this->stream === null) { + return; + } + + fclose($this->stream); + $this->stream = null; + + Signal::getInstance()->emit(strtolower($this->getAdapterType()).'Disconnected'); + } + + /** + * Reads data from the stream. + * + * @throws TransportException + */ + public function read(int $length = 4096): StringHelper + { + $this->connect(); + $this->waitForReadyRead(); + + $data = fread($this->stream, $length); + + if ($data === false) { + throw new TransportException("connection to server '".$this->config['host'].':'.$this->config['port']."' lost"); + } + + Signal::getInstance()->emit(strtolower($this->getAdapterType()).'DataRead', $data); + + return new StringHelper($data); + } + + /** + * Writes data to the stream. + * + * @throws TransportException + */ + public function send(string $data): void + { + $this->connect(); + + $written = fwrite($this->stream, $data); + + if ($written === false) { + throw new TransportException("connection to server '".$this->config['host'].':'.$this->config['port']."' lost"); + } + + Signal::getInstance()->emit(strtolower($this->getAdapterType()).'DataSend', $data); + } +} diff --git a/tests/DevLiveServer/ChannelGroupTest.php b/tests/DevLiveServer/ChannelGroupTest.php index c9e1ca02..1567b12a 100644 --- a/tests/DevLiveServer/ChannelGroupTest.php +++ b/tests/DevLiveServer/ChannelGroupTest.php @@ -27,6 +27,8 @@ class ChannelGroupTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $user_test_active; @@ -57,12 +59,13 @@ public function setUp(): void $this->ts3_unit_test_channel_name = str_replace('DEV_LIVE_SERVER_UNIT_TEST_CHANNEL=', '', preg_replace('#\n(?!\n)#', '', $env[7])); $this->user_test_active = str_replace('DEV_LIVE_SERVER_UNIT_TEST_USER_ACTIVE=', '', preg_replace('#\n(?!\n)#', '', $env[8])); $this->ts3_unit_test_userName = str_replace('DEV_LIVE_SERVER_UNIT_TEST_USER=', '', preg_replace('#\n(?!\n)#', '', $env[9])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&timeout=30'; } diff --git a/tests/DevLiveServer/ChannelTest.php b/tests/DevLiveServer/ChannelTest.php index cbf5e0a2..e6fdcdee 100644 --- a/tests/DevLiveServer/ChannelTest.php +++ b/tests/DevLiveServer/ChannelTest.php @@ -25,6 +25,8 @@ class ChannelTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -47,12 +49,13 @@ public function setUp(): void $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); $this->ts3_unit_test_channel_name = str_replace('DEV_LIVE_SERVER_UNIT_TEST_CHANNEL=', '', preg_replace('#\n(?!\n)#', '', $env[7])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&timeout=30'; } @@ -767,4 +770,14 @@ protected function onNotSuccessfulTest(Throwable $t): never parent::onNotSuccessfulTest($t); } + + /** + * @throws AdapterException + * @throws TransportException + * @throws ServerQueryException + */ + public function dev_reset_test_channel(Server $ts3VirtualServer): void + { + $ts3VirtualServer->channelGetByName('Play-Test')->delete(); + } } diff --git a/tests/DevLiveServer/ClientTest.php b/tests/DevLiveServer/ClientTest.php index c11aa20c..da853cf0 100644 --- a/tests/DevLiveServer/ClientTest.php +++ b/tests/DevLiveServer/ClientTest.php @@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase; use PlanetTeamSpeak\TeamSpeak3Framework\Exception\AdapterException; +use PlanetTeamSpeak\TeamSpeak3Framework\Exception\FileTransferException; use PlanetTeamSpeak\TeamSpeak3Framework\Exception\HelperException; use PlanetTeamSpeak\TeamSpeak3Framework\Exception\NodeException; use PlanetTeamSpeak\TeamSpeak3Framework\Exception\ServerQueryException; @@ -25,6 +26,8 @@ class ClientTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -43,6 +46,8 @@ class ClientTest extends TestCase private int $cgid; + private string $testPath = DIRECTORY_SEPARATOR.'tests\testsources'; + public function setUp(): void { //proof test active @@ -58,12 +63,13 @@ public function setUp(): void $this->user_test_active = str_replace('DEV_LIVE_SERVER_UNIT_TEST_USER_ACTIVE=', '', preg_replace('#\n(?!\n)#', '', $env[8])); $this->ts3_unit_test_userName = str_replace('DEV_LIVE_SERVER_UNIT_TEST_USER=', '', preg_replace('#\n(?!\n)#', '', $env[9])); $this->ts3_unit_test_userName2 = str_replace('DEV_LIVE_SERVER_UNIT_TEST_USER_EXTEND=', '', preg_replace('#\n(?!\n)#', '', $env[11])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&blocking=0'. '&timeout=30'; @@ -665,6 +671,95 @@ public function test_has_overwolf() $this->assertFalse($ts3_VirtualServer->getAdapter()->getTransport()->isConnected()); } + /** + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws FileTransferException + * @throws HelperException + */ + public function test_can_download_client_icon() + { + if ($this->user_test_active == 'false' || $this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + + $iconFile = getcwd().DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.'testsources'.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR.'Voice.png'; + $this->assertFileExists($iconFile); + $this->assertGreaterThan(0, filesize($iconFile)); + + $iconId = $ts3_VirtualServer->iconUpload($iconFile); + $signedIconId = $iconId > 0x7FFFFFFF ? $iconId - 0x100000000 : $iconId; + $iconName = 'icon_'.$iconId; + + $client = $ts3_VirtualServer->clientGetByName($this->ts3_unit_test_userName); + $client->permAssign(['i_icon_id'], $signedIconId); + + $permissions = $client->permList(true); + + $this->assertArrayHasKey('i_icon_id', $permissions); + $this->assertSame($signedIconId, (int) $permissions['i_icon_id']['permvalue']); + + $ts3_VirtualServer->clientListReset(); + $client = $ts3_VirtualServer->clientGetByName($this->ts3_unit_test_userName); + $content = $client->iconDownload(); + + $this->assertNotNull($content); + $this->assertGreaterThan(0, strlen($content->toString())); + + $downloadPath = getcwd().$this->testPath.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'download'; + $targetFile = $downloadPath.DIRECTORY_SEPARATOR.$iconName.'.png'; + + file_put_contents($targetFile, $content->toString()); + + $this->assertFileExists($targetFile); + $this->assertGreaterThan(0, filesize($targetFile)); + + $client->permRemove(['i_icon_id']); + $ts3_VirtualServer->iconDelete($iconId); + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + + $this->assertFalse($ts3_VirtualServer->getAdapter()->getTransport()->isConnected()); + } + + /** + * @throws AdapterException + * @throws TransportException + * @throws ServerQueryException + * @throws FileTransferException + * @throws HelperException + * @throws \Exception + */ + public function test_can_download_client_avatar() + { + if ($this->user_test_active == 'false' || $this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + $client = $ts3_VirtualServer->clientGetByName($this->ts3_unit_test_userName); + $content = $client->avatarDownload(); + + if ($content === null) { + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + $this->markTestIncomplete('Test client has no avatar set'); + } + + $this->assertGreaterThan(0, strlen($content->toString())); + + $downloadPath = getcwd().$this->testPath.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'download'; + $targetFile = $downloadPath.DIRECTORY_SEPARATOR.'avatar_'.$client['client_database_id'].'.png'; + file_put_contents($targetFile, $content->toString()); + + $this->assertFileExists($targetFile); + $this->assertGreaterThan(0, filesize($targetFile)); + + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + $this->assertFalse($ts3_VirtualServer->getAdapter()->getTransport()->isConnected()); + } + /** * @throws AdapterException * @throws ServerQueryException diff --git a/tests/DevLiveServer/ConnectionTest.php b/tests/DevLiveServer/ConnectionTest.php index 3cae0eb3..fc0d99a4 100644 --- a/tests/DevLiveServer/ConnectionTest.php +++ b/tests/DevLiveServer/ConnectionTest.php @@ -23,29 +23,34 @@ class ConnectionTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; private string $ts3_server_uri; + private string $serverQueryLoginName; + public function setUp(): void { //proof test active if (file_exists('./.env.testing')) { $env = file('./.env.testing'); - //get live server is available $this->active = str_replace('DEV_LIVE_SERVER_AVAILABLE=', '', preg_replace('#\n(?!\n)#', '', $env[2])); $this->host = str_replace('DEV_LIVE_SERVER_HOST=', '', preg_replace('#\n(?!\n)#', '', $env[3])); $this->queryPort = str_replace('DEV_LIVE_SERVER_QUERY_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[4])); $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); + $this->serverQueryLoginName = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_QUERY_LOGIN_NAME=', '', preg_replace('#\n(?!\n)#', '', $env[13])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&blocking=0'. '&timeout=30'; @@ -145,7 +150,7 @@ public function test_can_get_host_information() $ts3_host = TeamSpeak3::factory($this->ts3_server_uri); $port = $ts3_host->getParent()->serverSelectedPort(); - $this->assertEquals(9987, $port); + $this->assertEquals($this->serverPort, $port); $version = $ts3_host->version(); $this->assertIsArray($version); @@ -154,13 +159,13 @@ public function test_can_get_host_information() $this->assertEquals('Linux', $version['platform']); $this->assertArrayHasKey('build', $version); - $serverID = $ts3_host->serverIdGetByPort(9987); + $serverID = $ts3_host->serverIdGetByPort($this->serverPort); $this->assertIsInt($serverID); $this->assertEquals(1, $serverID); $PortByID = $ts3_host->serverGetPortById($serverID); $this->assertIsInt($PortByID); - $this->assertEquals(9987, $PortByID); + $this->assertEquals($this->serverPort, $PortByID); $server = $ts3_host->servergetByname('UnitTestServer'); $this->assertIsArray($server); @@ -240,8 +245,8 @@ public function test_can_handle_log() } $ts3_host = TeamSpeak3::factory($this->ts3_server_uri); - $ts3_host->serverGetByPort(9987)->logAdd('UnitTest', TeamSpeak3::LOGLEVEL_DEBUG); - $log = $ts3_host->serverGetByPort(9987)->logView(); + $ts3_host->serverGetByPort($this->serverPort)->logAdd('UnitTest', TeamSpeak3::LOGLEVEL_DEBUG); + $log = $ts3_host->serverGetByPort($this->serverPort)->logView(); $this->assertIsArray($log); $this->assertIsString($log[29]); $this->assertStringContainsString('UnitTest', $log[29]); @@ -270,7 +275,7 @@ public function test_can_handle_server_query() foreach ($queryLoginlist as $queryLogin) { $this->assertIsString($queryLogin['client_login_name']); - $this->assertEquals('ts3-bot-dev', $queryLogin['client_login_name']); + $this->assertEquals($this->serverQueryLoginName, $queryLogin['client_login_name']); } $ts3_host->getAdapter()->getTransport()->disconnect(); diff --git a/tests/DevLiveServer/FileTransferTest.php b/tests/DevLiveServer/FileTransferTest.php new file mode 100644 index 00000000..5ec07ddc --- /dev/null +++ b/tests/DevLiveServer/FileTransferTest.php @@ -0,0 +1,440 @@ +active = str_replace('DEV_LIVE_SERVER_AVAILABLE=', '', preg_replace('#\n(?!\n)#', '', $env[2])); + $this->host = str_replace('DEV_LIVE_SERVER_HOST=', '', preg_replace('#\n(?!\n)#', '', $env[3])); + $this->queryPort = str_replace('DEV_LIVE_SERVER_QUERY_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[4])); + $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); + $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); + $this->ts3_unit_test_channel_name = str_replace('DEV_LIVE_SERVER_UNIT_TEST_CHANNEL=', '', preg_replace('#\n(?!\n)#', '', $env[7])); + } else { + $this->active = 'false'; + } + + $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. + '/?server_port='.$this->serverPort. + '&no_query_clients=0'. + '&blocking=0'. + '&timeout=30'; + } + + /** + * @throws AdapterException + * @throws ServerQueryException + * @throws TransportException + * @throws \Exception + */ + public function test_can_file_upload(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + + $channel = $ts3_Host->channelGetByName('UnitTest'); + $channel->fileUpload('/test.txt', 'Hello World', overwrite: true); + $cFileList = $channel->fileList(); + + $this->assertCount(1, $cFileList); + $this->assertEquals('test.txt', $cFileList[0]['name']); + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws FileTransferException + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws HelperException + */ + public function test_can_file_download(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + + $channel = $ts3_Host->channelGetByName('UnitTest'); + $content = $channel->fileDownload('/test.txt'); + file_put_contents(getcwd().$this->testPath.'\test.txt', $content->toString()); + + $this->assertFileExists(getcwd().$this->testPath.'\test.txt'); + $this->assertEquals('Hello World', $content->toString()); + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws HelperException + */ + public function test_can_file_delete(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + $channel = $ts3_Host->channelGetByName('UnitTest'); + $cFileList = $channel->fileList(); + + if (count($cFileList) > 0) { + $channel->fileDelete('', '/test.txt'); + } + + $cFileList = $channel->fileList(); + $this->assertCount(0, $cFileList); + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws AdapterException + * @throws FileTransferException + * @throws TransportException + * @throws ServerQueryException + * @throws HelperException + */ + public function test_can_icon_upload(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + $iconId = $ts3_Host->iconUpload(getcwd().$this->testPath.'\icons\upload\ChannelAdmin.png'); + $iconList = $ts3_Host->iconList(); + + $this->assertNotEmpty($iconList); + $this->assertContains('icon_'.$iconId, array_column($iconList, 'name')); + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws FileTransferException + * @throws AdapterException + * @throws TransportException + * @throws ServerQueryException + * @throws HelperException + */ + public function test_can_icon_download(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + $ts3_Host->iconUpload(getcwd().$this->testPath.'\icons\upload\ChannelAdmin.png'); + $iconList = $ts3_Host->iconList(); + + if ($iconList === []) { + $this->markTestIncomplete('No icons available for download'); + } + + $downloadPath = getcwd().$this->testPath.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'download'; + + foreach ($iconList as $icon) { + $this->assertArrayHasKey('name', $icon); + + $content = $ts3_Host->iconDownload($icon['name']); + + $this->assertNotNull($content); + + $targetFile = $downloadPath.DIRECTORY_SEPARATOR.$icon['name'].'.png'; + file_put_contents($targetFile, $content->toString()); + + $this->assertFileExists($targetFile); + $this->assertGreaterThan(0, filesize($targetFile)); + } + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws AdapterException + * @throws FileTransferException + * @throws TransportException + * @throws ServerQueryException + * @throws HelperException + */ + public function test_can_icon_delete(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_Host = TeamSpeak3::factory($this->ts3_server_uri); + $iconID = $ts3_Host->iconUpload(getcwd().$this->testPath.'\icons\upload\ChannelAdmin.png'); + + $ts3_Host->iconDelete('icon_'.$iconID); + + $iconList = $ts3_Host->iconList(); + $this->assertNotContains('icon_'.$iconID, array_column($iconList, 'name')); + + $ts3_Host->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws NodeException + * @throws FileTransferException + * @throws HelperException + */ + public function test_can_upload_servergroup_icon(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + $this->set_play_test_servergroup($ts3_VirtualServer); + + $iconFile = getcwd().DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.'testsources'.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR.'Registered.png'; + $iconId = $ts3_VirtualServer->iconUpload($iconFile); + $serverGroup = $ts3_VirtualServer->serverGroupGetById($this->sgid); + $serverGroup->permAssign(['i_icon_id'], $iconId); + + $permissions = $serverGroup->permList(true); + + $this->assertArrayHasKey('i_icon_id', $permissions); + $this->assertSame($iconId, (int) $permissions['i_icon_id']['permvalue']); + + $this->unset_play_test_servergroup($ts3_VirtualServer); + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws HelperException + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws NodeException + * @throws FileTransferException + */ + public function test_can_download_servergroup_icon(): void + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + $this->set_play_test_servergroup($ts3_VirtualServer); + + $iconFile = getcwd().DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.'testsources'.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR.'Registered.png'; + $this->assertFileExists($iconFile); + $this->assertGreaterThan(0, filesize($iconFile)); + + $iconId = $ts3_VirtualServer->iconUpload($iconFile); + $iconName = 'icon_'.$iconId; + + $serverGroup = $ts3_VirtualServer->serverGroupGetById($this->sgid); + $serverGroup->permAssign(['i_icon_id'], $iconId); + + $ts3_VirtualServer->serverGroupListReset(); + $serverGroup = $ts3_VirtualServer->serverGroupGetById($this->sgid); + $content = $serverGroup->iconDownload(); + + $this->assertNotNull($content); + $this->assertGreaterThan(0, strlen($content->toString())); + + $downloadPath = getcwd().$this->testPath.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'download'; + + $targetFile = $downloadPath.DIRECTORY_SEPARATOR.$iconName.'.png'; + file_put_contents($targetFile, $content->toString()); + + $this->assertFileExists($targetFile); + $this->assertGreaterThan(0, filesize($targetFile)); + + $ts3_VirtualServer->iconDelete($iconId); + $this->unset_play_test_servergroup($ts3_VirtualServer); + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + $this->assertFalse($ts3_VirtualServer->getAdapter()->getTransport()->isConnected()); + } + + /** + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws FileTransferException + * @throws HelperException + */ + public function test_can_upload_channel_icon() + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + $cid = $this->set_play_test_channel($ts3_VirtualServer); + + $iconFile = getcwd().DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.'testsources'.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR.'Guest.png'; + $iconId = $ts3_VirtualServer->iconUpload($iconFile); + $signedIconId = $iconId > 0x7FFFFFFF ? $iconId - 0x100000000 : $iconId; + + $channel = $ts3_VirtualServer->channelGetById($cid); + $channel->permAssign(['i_icon_id'], $signedIconId); + + $permissions = $channel->permList(true); + + $this->assertArrayHasKey('i_icon_id', $permissions); + $this->assertSame($signedIconId, (int) $permissions['i_icon_id']['permvalue']); + + $this->unset_play_test_channel($ts3_VirtualServer); + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + } + + /** + * @throws HelperException + * @throws TransportException + * @throws ServerQueryException + * @throws AdapterException + * @throws FileTransferException + */ + public function test_can_download_channel_icon() + { + if ($this->active == 'false') { + $this->markTestSkipped('DevLiveServer ist not active'); + } + + $ts3_VirtualServer = TeamSpeak3::factory($this->ts3_server_uri); + $cid = $this->set_play_test_channel($ts3_VirtualServer); + + $iconFile = getcwd().DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.'testsources'.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'upload'.DIRECTORY_SEPARATOR.'Guest.png'; + $this->assertFileExists($iconFile); + $this->assertGreaterThan(0, filesize($iconFile)); + + $iconId = $ts3_VirtualServer->iconUpload($iconFile); + $signedIconId = $iconId > 0x7FFFFFFF ? $iconId - 0x100000000 : $iconId; + $iconName = 'icon_'.$iconId; + + $channel = $ts3_VirtualServer->channelGetById($cid); + $channel->permAssign(['i_icon_id'], $signedIconId); + + $permissions = $channel->permList(true); + + $this->assertArrayHasKey('i_icon_id', $permissions); + $this->assertSame($signedIconId, (int) $permissions['i_icon_id']['permvalue']); + + $ts3_VirtualServer->channelListReset(); + $channel = $ts3_VirtualServer->channelGetById($cid); + $content = $channel->iconDownload(); + + $this->assertNotNull($content); + $this->assertGreaterThan(0, strlen($content->toString())); + + $downloadPath = getcwd().$this->testPath.DIRECTORY_SEPARATOR.'icons'.DIRECTORY_SEPARATOR.'download'; + $targetFile = $downloadPath.DIRECTORY_SEPARATOR.$iconName.'.png'; + + file_put_contents($targetFile, $content->toString()); + + $this->assertFileExists($targetFile); + $this->assertGreaterThan(0, filesize($targetFile)); + + $ts3_VirtualServer->iconDelete($iconId); + $this->unset_play_test_channel($ts3_VirtualServer); + $ts3_VirtualServer->getAdapter()->getTransport()->disconnect(); + $this->assertFalse($ts3_VirtualServer->getAdapter()->getTransport()->isConnected()); + } + + /** + * @throws AdapterException + * @throws TransportException + * @throws ServerQueryException + */ + private function set_play_test_servergroup(Server $ts3VirtualServer): void + { + $this->sgid = $ts3VirtualServer->serverGroupCreate('UnitTest', 1); + } + + /** + * @param Server $ts3_VirtualServer + * @throws AdapterException + * @throws ServerQueryException + * @throws TransportException + */ + public function unset_play_test_servergroup(Server $ts3_VirtualServer): void + { + $ts3_VirtualServer->serverGroupDelete($this->sgid); + } + + /** + * @throws AdapterException + * @throws TransportException + * @throws ServerQueryException + */ + private function set_play_test_channel(Server $ts3VirtualServer): int + { + $cid = $ts3VirtualServer->channelGetByName($this->ts3_unit_test_channel_name)->getId(); + + $createdCID = $ts3VirtualServer->channelCreate(['channel_name' => 'Play-Test', 'channel_flag_permanent' => 1, 'cpid' => $cid]); + $this->test_cid = $createdCID; + + return $createdCID; + } + + /** + * @throws AdapterException + * @throws ServerQueryException + * @throws HelperException + */ + public function unset_play_test_channel($ts3_VirtualServer): void + { + $ts3_VirtualServer->channelDelete($this->test_cid, true); + } +} diff --git a/tests/DevLiveServer/FoundIssuesOnPublicProjectsTest.php b/tests/DevLiveServer/FoundIssuesOnPublicProjectsTest.php index 3bacda92..f537a4b7 100644 --- a/tests/DevLiveServer/FoundIssuesOnPublicProjectsTest.php +++ b/tests/DevLiveServer/FoundIssuesOnPublicProjectsTest.php @@ -24,6 +24,8 @@ class FoundIssuesOnPublicProjectsTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -43,12 +45,13 @@ public function setUp(): void $this->queryPort = str_replace('DEV_LIVE_SERVER_QUERY_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[4])); $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&timeout=30'; } diff --git a/tests/DevLiveServer/RefactorFunctionsTest.php b/tests/DevLiveServer/RefactorFunctionsTest.php index 123a8e63..d540cb12 100644 --- a/tests/DevLiveServer/RefactorFunctionsTest.php +++ b/tests/DevLiveServer/RefactorFunctionsTest.php @@ -27,6 +27,8 @@ class RefactorFunctionsTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -46,12 +48,13 @@ public function setUp(): void $this->queryPort = str_replace('DEV_LIVE_SERVER_QUERY_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[4])); $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&timeout=30'; } diff --git a/tests/DevLiveServer/ServerGroupTest.php b/tests/DevLiveServer/ServerGroupTest.php index e0a01cd1..d40b3396 100644 --- a/tests/DevLiveServer/ServerGroupTest.php +++ b/tests/DevLiveServer/ServerGroupTest.php @@ -28,6 +28,8 @@ class ServerGroupTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -49,12 +51,13 @@ public function setUp(): void $this->queryPort = str_replace('DEV_LIVE_SERVER_QUERY_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[4])); $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&timeout=30'; } diff --git a/tests/DevLiveServer/SignalTest.php b/tests/DevLiveServer/SignalTest.php index 47960741..53eb3189 100644 --- a/tests/DevLiveServer/SignalTest.php +++ b/tests/DevLiveServer/SignalTest.php @@ -31,6 +31,8 @@ class SignalTest extends TestCase private string $queryPort; + private string $serverPort; + private string $user; private string $password; @@ -55,12 +57,13 @@ public function setUp(): void $this->user = str_replace('DEV_LIVE_SERVER_QUERY_USER=', '', preg_replace('#\n(?!\n)#', '', $env[5])); $this->password = str_replace('DEV_LIVE_SERVER_QUERY_USER_PASSWORD=', '', preg_replace('#\n(?!\n)#', '', $env[6])); $this->ts3_unit_test_signals = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SIGNALS=', '', preg_replace('#\n(?!\n)#', '', $env[10])); + $this->serverPort = str_replace('DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=', '', preg_replace('#\n(?!\n)#', '', $env[12])); } else { $this->active = 'false'; } $this->ts3_server_uri = 'serverquery://'.$this->user.':'.$this->password.'@'.$this->host.':'.$this->queryPort. - '/?server_port=9987'. + '/?server_port='.$this->serverPort. '&no_query_clients=0'. '&blocking=0'. '&timeout=30'; diff --git a/tests/testsources/.gitignore b/tests/testsources/.gitignore new file mode 100644 index 00000000..62a18f77 --- /dev/null +++ b/tests/testsources/.gitignore @@ -0,0 +1,4 @@ +* +icons/download* +!.gitignore +!/icons/upload* diff --git a/tests/testsources/icons/upload/Avatar-default-512.png b/tests/testsources/icons/upload/Avatar-default-512.png new file mode 100644 index 00000000..b5a89168 Binary files /dev/null and b/tests/testsources/icons/upload/Avatar-default-512.png differ diff --git a/tests/testsources/icons/upload/ChannelAdmin.png b/tests/testsources/icons/upload/ChannelAdmin.png new file mode 100644 index 00000000..33d8ca9c Binary files /dev/null and b/tests/testsources/icons/upload/ChannelAdmin.png differ diff --git a/tests/testsources/icons/upload/Guest.png b/tests/testsources/icons/upload/Guest.png new file mode 100644 index 00000000..be036179 Binary files /dev/null and b/tests/testsources/icons/upload/Guest.png differ diff --git a/tests/testsources/icons/upload/Registered.png b/tests/testsources/icons/upload/Registered.png new file mode 100644 index 00000000..6a781dfb Binary files /dev/null and b/tests/testsources/icons/upload/Registered.png differ diff --git a/tests/testsources/icons/upload/Voice.png b/tests/testsources/icons/upload/Voice.png new file mode 100644 index 00000000..39d33b74 Binary files /dev/null and b/tests/testsources/icons/upload/Voice.png differ