diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 0355c33..14ce69a 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -8,7 +8,7 @@ jobs: fail-fast: false matrix: operating-system: [ubuntu-latest] - php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3'] + php-versions: ['8.1', '8.2', '8.3', '8.4'] steps: - name: Checkout @@ -25,7 +25,7 @@ jobs: run: composer install --prefer-dist --no-progress --no-suggest --no-interaction - name: phpcs - run: vendor/bin/php-cs-fixer fix --diff --dry-run -v + run: PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix --diff --dry-run -v - name: psalm run: vendor/bin/psalm --show-info=false diff --git a/.gitignore b/.gitignore index 6e26b63..6561bc0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ stats.log # php-cs-fixer .php-cs-fixer.cache +/.phpunit.cache/test-results diff --git a/composer.json b/composer.json index 5f1b5e7..dcc2572 100644 --- a/composer.json +++ b/composer.json @@ -18,12 +18,12 @@ } ], "require": { - "php": ">= 7.3 || ^8" + "php": "^8.1" }, "require-dev": { - "phpunit/phpunit": "^9", - "vimeo/psalm": "^4.6", - "friendsofphp/php-cs-fixer": "^3.0" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^6.12", + "friendsofphp/php-cs-fixer": "^3.75" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d42bd40..db9cc38 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,13 +1,24 @@ - - - - ./src - - - - - tests/unit - - + + + + tests/unit + + + + + ./src + + diff --git a/psalm.xml b/psalm.xml index 622e23e..e3032bf 100644 --- a/psalm.xml +++ b/psalm.xml @@ -51,5 +51,10 @@ + + + + + diff --git a/src/Client.php b/src/Client.php index a8be5d8..d50aada 100644 --- a/src/Client.php +++ b/src/Client.php @@ -129,7 +129,7 @@ public function timing(string $key, float $value, float $sampleRate = 1.0, array */ public function startTiming(string $key, array $tags = []): void { - $timingKey = $key . md5(json_encode($tags)); + $timingKey = $key . md5((string)json_encode($tags)); $this->timings[$timingKey] = gettimeofday(true); } @@ -145,7 +145,7 @@ public function startTiming(string $key, array $tags = []): void public function endTiming(string $key, float $sampleRate = 1.0, array $tags = []): ?float { $end = gettimeofday(true); - $timingKey = $key . md5(json_encode($tags)); + $timingKey = $key . md5((string)json_encode($tags)); if (isset($this->timings[$timingKey])) { $timing = ($end - $this->timings[$timingKey]) * 1000; @@ -266,10 +266,10 @@ private function send(string $key, $value, string $type, float $sampleRate, arra $key = $this->namespace . '.' . $key; } - $message = $key . ':' . $value . '|' . $type; + $message = $key . ':' . ((string)$value) . '|' . $type; if ($sampleRate < 1) { - $sampledData = $message . '|@' . $sampleRate; + $sampledData = $message . '|@' . ((string)$sampleRate); } else { $sampledData = $message; } diff --git a/src/Connection/File.php b/src/Connection/File.php index 70d67d3..ab7aff2 100644 --- a/src/Connection/File.php +++ b/src/Connection/File.php @@ -32,7 +32,7 @@ public function __construct(string $filePath, string $mode = "a+") private function open(): void { - $this->handle = @fopen($this->filePath, $this->mode); + $this->handle = @fopen($this->filePath, $this->mode) ?: null; } public function send(string $message): void diff --git a/src/Connection/InMemory.php b/src/Connection/InMemory.php index 4a9f9f8..9d276fb 100644 --- a/src/Connection/InMemory.php +++ b/src/Connection/InMemory.php @@ -15,7 +15,7 @@ class InMemory implements Connection /** * @var string[] */ - private $messages = []; + private array $messages = []; public function send(string $message): void { diff --git a/src/Connection/InetSocket.php b/src/Connection/InetSocket.php index e2a7946..aa0e335 100644 --- a/src/Connection/InetSocket.php +++ b/src/Connection/InetSocket.php @@ -6,6 +6,8 @@ use Domnikl\Statsd\Connection; +use function ini_get; + abstract class InetSocket implements Connection { private const LINE_DELIMITER = "\n"; @@ -14,34 +16,30 @@ abstract class InetSocket implements Connection /** * host name - * * @var string */ protected $host; /** * port number - * - * @var int + * @var int<1, 65535> */ protected $port; /** * Socket timeout - * - * @var int + * @var int<0, max> */ private $timeout; /** * Persistent connection - * * @var bool */ - private $persistent = false; + private $persistent; /** - * @var int + * @var int<1, max> */ private $maxPayloadSize; @@ -49,8 +47,8 @@ abstract class InetSocket implements Connection * instantiates the Connection object and a real connection to statsd * * @param string $host Statsd hostname - * @param int $port Statsd port - * @param ?int $timeout Connection timeout + * @param int<1, 65535> $port Statsd port + * @param ?int<0, max> $timeout Connection timeout * @param bool $persistent (default FALSE) Use persistent connection or not * @param int $mtu Maximum Transmission Unit (default: 1500) */ @@ -64,13 +62,23 @@ public function __construct( $this->host = $host; $this->port = $port; $this->persistent = $persistent; - $this->maxPayloadSize = $mtu - + $maxPayloadSize = $mtu - self::IP_HEADER_SIZE - $this->getProtocolHeaderSize() - strlen(self::LINE_DELIMITER); + if ($maxPayloadSize <= 0) { + throw new \InvalidArgumentException( + 'The maximum payload size must be greater than 0. Please check the MTU value.' + ); + } + + $this->maxPayloadSize = $maxPayloadSize; + if ($timeout === null) { - $this->timeout = (int) ini_get('default_socket_timeout'); + /** @var int<0, max> $timeout */ + $timeout = (int) ini_get('default_socket_timeout'); + $this->timeout = $timeout; } else { $this->timeout = $timeout; } diff --git a/src/Connection/TcpSocketException.php b/src/Connection/TcpSocketException.php index 79ce50f..4820bae 100644 --- a/src/Connection/TcpSocketException.php +++ b/src/Connection/TcpSocketException.php @@ -6,7 +6,7 @@ class TcpSocketException extends \RuntimeException { - public function __construct(string $host, int $port, string $message, \Exception $previous = null) + public function __construct(string $host, int $port, string $message, ?\Exception $previous = null) { parent::__construct( sprintf('Couldn\'t connect to host "%s:%d": %s', $host, $port, $message), diff --git a/src/Connection/UdpSocket.php b/src/Connection/UdpSocket.php index 827a9b3..870559a 100644 --- a/src/Connection/UdpSocket.php +++ b/src/Connection/UdpSocket.php @@ -69,9 +69,9 @@ protected function connect(string $host, int $port, int $timeout, bool $persiste $url = 'udp://' . $host; if ($persistent) { - $this->socket = @pfsockopen($url, $port, $errorNumber, $errorMessage, $timeout); + $this->socket = @pfsockopen($url, $port, $errorNumber, $errorMessage, $timeout) ?: null; } else { - $this->socket = @fsockopen($url, $port, $errorNumber, $errorMessage, $timeout); + $this->socket = @fsockopen($url, $port, $errorNumber, $errorMessage, $timeout) ?: null; } } diff --git a/tests/unit/ClientTest.php b/tests/unit/ClientTest.php index 7dbe98c..83678de 100644 --- a/tests/unit/ClientTest.php +++ b/tests/unit/ClientTest.php @@ -5,6 +5,8 @@ namespace Domnikl\Test\Statsd; use Domnikl\Statsd\Client as Client; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; class ClientTest extends TestCase @@ -58,7 +60,7 @@ public function testCountWithFloatValue() ); } - public function sampleRateData() + public static function sampleRateData() { return [ [0.9, 1, '0.9'], @@ -66,10 +68,8 @@ public function sampleRateData() ]; } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testCountWithSamplingRate(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -82,10 +82,8 @@ public function testCountWithSamplingRate(float $globalSampleRate, float $sample ); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testCountWithSamplingRateAndTags(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -107,10 +105,8 @@ public function testIncrement() ); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testIncrementWithSamplingRate(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -123,10 +119,8 @@ public function testIncrementWithSamplingRate(float $globalSampleRate, float $sa ); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testIncrementWithSamplingRateAndTags(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -148,10 +142,8 @@ public function testDecrement() ); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testDecrementWithSamplingRate(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -164,10 +156,8 @@ public function testDecrementWithSamplingRate(float $globalSampleRate, float $sa ); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testDecrementWithSamplingRateAndTags(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -190,10 +180,8 @@ public function testCanMeasureTimingWithClosure() } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testTimingWithSamplingRate(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -232,10 +220,8 @@ public function testEndTimingReturnsTiming() $this->assertGreaterThanOrEqual($sleep / 1000, $this->client->endTiming($key)); } - /** - * @dataProvider sampleRateData - * @group sampling - */ + #[DataProvider('sampleRateData')] + #[Group('sampling')] public function testStartEndTimingWithSamplingRate(float $globalSampleRate, float $sampleRate, string $expectedSampleRate) { $client = new Client($this->connection, 'test', $globalSampleRate); @@ -265,9 +251,7 @@ public function testTimeClosure() ); } - /** - * @group memory - */ + #[Group('memory')] public function testMemory() { $this->client->memory('foo.bar'); @@ -277,9 +261,7 @@ public function testMemory() ); } - /** - * @group memory - */ + #[Group('memory')] public function testMemoryProfile() { $this->client->startMemoryProfile('foo.bar'); diff --git a/tests/unit/Connection/FileTest.php b/tests/unit/Connection/FileTest.php index a58513e..22cee85 100644 --- a/tests/unit/Connection/FileTest.php +++ b/tests/unit/Connection/FileTest.php @@ -5,6 +5,7 @@ namespace Domnikl\Test\Statsd\Connection; use Domnikl\Statsd\Connection\File; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; class FileTest extends TestCase @@ -22,8 +23,8 @@ public function testSend() /** * @param string $metric - * @dataProvider dataForSendWrongData */ + #[DataProvider('dataForSendWrongData')] public function testSendWrongData(string $metric) { $connection = new File('php://memory'); @@ -34,7 +35,7 @@ public function testSendWrongData(string $metric) /** * @return string[] */ - public function dataForSendWrongData() + public static function dataForSendWrongData() { return [ [''],