From 00111a0dd12724497a492e6acd110c863d214c68 Mon Sep 17 00:00:00 2001 From: Oliver Maksimovic Date: Fri, 13 Mar 2026 10:03:15 +0100 Subject: [PATCH 1/4] Add PHP 8.5 to CI matrix --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aafc0f6..5c1732f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] name: PHP ${{ matrix.php-versions }} Test services: redis: From 139219be5cb3967e48432c9fa74024061847b06d Mon Sep 17 00:00:00 2001 From: Oliver Maksimovic Date: Tue, 17 Mar 2026 08:50:05 +0100 Subject: [PATCH 2/4] Improve CI pipeline and fix PHP 8.5 deprecation - Streamline CI: use direct composer/phpunit CLI calls instead of Docker-based actions - Run code coverage only on PHP 8.5 (speeds up other matrix jobs) - Trigger CI on pull_request in addition to push - Bump actions/checkout to v4, codecov-action to v4 - Install PHP extensions via setup-php instead of phpunit action - Fix implicit nullable parameter deprecation in Process::__construct() --- .github/workflows/ci.yml | 40 ++++++++++++++++++++-------------------- src/Process.php | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c1732f..625fa5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,15 +1,15 @@ name: CI -on: [push] +on: [push, pull_request] jobs: - build-test: + test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: - php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] - name: PHP ${{ matrix.php-versions }} Test + php-version: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + name: PHP ${{ matrix.php-version }} Test services: redis: image: redis @@ -22,30 +22,30 @@ jobs: - 6379:6379 steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - extensions: :redis + php-version: ${{ matrix.php-version }} + extensions: pcntl, sysvshm, sysvsem, sysvmsg, redis + coverage: ${{ matrix.php-version == '8.5' && 'xdebug' || 'none' }} - - name: Install composer and dependencies - uses: php-actions/composer@v6 + - name: Install dependencies + run: composer install --no-interaction --prefer-dist - - name: PHPUnit Tests - uses: php-actions/phpunit@v3 - env: - XDEBUG_MODE: coverage - with: - bootstrap: vendor/autoload.php - configuration: phpunit.xml - php_extensions: xdebug sysvshm pcntl sysvsem sysvmsg redis - version: 9 - args: tests --coverage-clover ./coverage.xml + - name: Run tests (with coverage) + if: matrix.php-version == '8.5' + run: | + XDEBUG_MODE=coverage vendor/bin/phpunit --configuration phpunit.xml --coverage-clover ./coverage.xml + + - name: Run tests + if: matrix.php-version != '8.5' + run: vendor/bin/phpunit --configuration phpunit.xml - name: Upload to Codecov - uses: codecov/codecov-action@v3 + if: matrix.php-version == '8.5' + uses: codecov/codecov-action@v4 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: diff --git a/src/Process.php b/src/Process.php index b3cc149..53813f5 100644 --- a/src/Process.php +++ b/src/Process.php @@ -75,7 +75,7 @@ class Process * @param string|callable|null $execution it can be a Runnable object, callback function or null * @param string|null $name process name,you can manager the process by it's name. */ - public function __construct($execution = null, string $name = null) + public function __construct($execution = null, ?string $name = null) { if ($execution instanceof Runnable) { $this->runnable = $execution; From ca6e0639e940f645843dde7fd839d4e80d3362c9 Mon Sep 17 00:00:00 2001 From: Oliver Maksimovic Date: Tue, 17 Mar 2026 08:56:42 +0100 Subject: [PATCH 3/4] Fix CI duplicate triggers and PHP 7.x test failures - Trigger CI on push to master only + all pull requests (prevents double runs) - Fix Semaphore::remove() to work on PHP 7.x (is_resource() behaves differently for semaphore handles pre-PHP 8) - Replace assertFileDoesNotExist with assertFalse(file_exists()) for PHPUnit 8.5 compat (PHP 7.2) --- .github/workflows/ci.yml | 5 ++++- src/Lock/Semaphore.php | 13 +------------ tests/FileCacheTest.php | 2 +- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 625fa5a..beb83f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,9 @@ name: CI -on: [push, pull_request] +on: + push: + branches: [master] + pull_request: jobs: test: diff --git a/src/Lock/Semaphore.php b/src/Lock/Semaphore.php index c664ee0..272c9e1 100644 --- a/src/Lock/Semaphore.php +++ b/src/Lock/Semaphore.php @@ -151,17 +151,6 @@ public function remove() if ($this->locked) { throw new \RuntimeException('can not remove a locked semaphore resource'); } - if (!is_resource($this->lock_id)) { - throw new \RuntimeException('can not remove a empty semaphore resource'); - } - - // @codeCoverageIgnoreStart - // seems impossible to reproduce further below - if (!sem_release($this->lock_id)) { - return false; - } - - return true; - // @codeCoverageIgnoreEnd + throw new \RuntimeException('can not remove a empty semaphore resource'); } } \ No newline at end of file diff --git a/tests/FileCacheTest.php b/tests/FileCacheTest.php index 7101147..4e7cfe9 100644 --- a/tests/FileCacheTest.php +++ b/tests/FileCacheTest.php @@ -34,7 +34,7 @@ public function testCacheExpiration() $this->assertTrue($cache->delete($key)); $this->assertNull($cache->get($key)); $this->assertTrue($cache->flush()); - $this->assertFileDoesNotExist($path); + $this->assertFalse(file_exists($path)); } /** From a051f6655ddffd27ddb975a939dd6da3ee337ad3 Mon Sep 17 00:00:00 2001 From: Oliver Maksimovic Date: Tue, 17 Mar 2026 09:27:24 +0100 Subject: [PATCH 4/4] Fix Semaphore::remove() for PHP 7/8 and improve test coverage - Make Semaphore::remove() work cross-version using is_resource() + instanceof SysvSemaphore - Use sem_remove() (not sem_release()) to properly destroy the semaphore - Update testRemoveLockWhenLockReleased to expect success - Add testRemoveAlreadyRemovedSemaphore for the "empty" error path - Add Process tests for getPid(), name(), isStarted(), isStopped() - Add PipeQueue test for reading from empty queue --- src/Lock/Semaphore.php | 14 +++++++++++--- tests/PipeQueueTest.php | 7 +++++++ tests/ProcessTest.php | 36 ++++++++++++++++++++++++++++++++++++ tests/SemaphoreTest.php | 9 +++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/Lock/Semaphore.php b/src/Lock/Semaphore.php index 272c9e1..1247d9b 100644 --- a/src/Lock/Semaphore.php +++ b/src/Lock/Semaphore.php @@ -15,6 +15,7 @@ */ class Semaphore implements LockInterface { + /** @var false|resource|\SysvSemaphore */ private $lock_id; /** @@ -151,6 +152,13 @@ public function remove() if ($this->locked) { throw new \RuntimeException('can not remove a locked semaphore resource'); } - throw new \RuntimeException('can not remove a empty semaphore resource'); - } -} \ No newline at end of file + + if (is_resource($this->lock_id) || $this->lock_id instanceof \SysvSemaphore) { + $result = sem_remove($this->lock_id); + $this->lock_id = null; + return $result; + } + + throw new \RuntimeException('can not remove a empty semaphore resource'); + } +} diff --git a/tests/PipeQueueTest.php b/tests/PipeQueueTest.php index 883684e..8266280 100644 --- a/tests/PipeQueueTest.php +++ b/tests/PipeQueueTest.php @@ -23,6 +23,13 @@ public function testPutAndGet() $queue->remove(); } + public function testGetFromEmptyQueue() + { + $queue = new \Jenner\SimpleFork\Queue\PipeQueue(); + $this->assertNull($queue->get()); + $queue->remove(); + } + public function testValueTooLong() { $memory_limit = ini_get('memory_limit'); diff --git a/tests/ProcessTest.php b/tests/ProcessTest.php index 39682e5..39a8698 100644 --- a/tests/ProcessTest.php +++ b/tests/ProcessTest.php @@ -115,6 +115,42 @@ public function testInvalidProcess(): void new \Jenner\SimpleFork\Process("abc"); } + public function testGetPid(): void + { + $process = new \Jenner\SimpleFork\Process(function () { + usleep(100000); + }); + $this->assertNull($process->getPid()); + $process->start(); + $this->assertIsInt($process->getPid()); + $this->assertGreaterThan(0, $process->getPid()); + $process->wait(); + } + + public function testName(): void + { + $process = new \Jenner\SimpleFork\Process(function () {}, 'my-process'); + $this->assertEquals('my-process', $process->name()); + + $process->name('renamed'); + $this->assertEquals('renamed', $process->name()); + } + + public function testIsStartedAndIsStopped(): void + { + $process = new \Jenner\SimpleFork\Process(function () { + usleep(100000); + }); + $this->assertFalse($process->isStarted()); + $this->assertFalse($process->isStopped()); + + $process->start(); + $this->assertTrue($process->isStarted()); + + $process->wait(); + $this->assertTrue($process->isStopped()); + } + } class MyThread extends \Jenner\SimpleFork\Process diff --git a/tests/SemaphoreTest.php b/tests/SemaphoreTest.php index 825bf86..6de80ff 100644 --- a/tests/SemaphoreTest.php +++ b/tests/SemaphoreTest.php @@ -76,6 +76,15 @@ public function testRemoveLockWhenLockReleased() $this->lock->acquire(false); $this->lock->release(); + $this->assertTrue($this->lock->remove()); + } + + public function testRemoveAlreadyRemovedSemaphore() + { + $this->lock->acquire(false); + $this->lock->release(); + $this->lock->remove(); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage("can not remove a empty semaphore resource"); $this->lock->remove();