Repository navigation
Improve #169: Test coverage for framework bridges - #175
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review: 1
Please check the settings in the CodeRabbit UI or the
|
b108461 to
2a924c1
Compare
bialaps
left a comment
There was a problem hiding this comment.
One test-isolation issue in the Symfony bridge suite (inline). The remaining comments are documentation accuracy.
| self::assertInstanceOf(ZammadClient::class, $container->get(ZammadClient::class)); | ||
| } | ||
|
|
||
| public function testMissingTokenFailsWithTheLibrarysOwnMessage(): void |
There was a problem hiding this comment.
This test depends on the shell environment. env(ZAMMAD_TOKEN) set as a container parameter is only a fallback: Symfony reads $_ENV, $_SERVER and getenv() first, and uses the parameter only when the variable is absent (EnvVarProcessor.php L170-L171, fallback at L219-L224).
Reproduced on this branch (symfony/dependency-injection 8.1, PHP 8.5): with a clean environment all 10 tests pass; with ZAMMAD_TOKEN exported, as examples/cookbook/README.md instructs, this test fails:
1) ZammadAPIClient\Tests\Bridge\Symfony\SymfonyBundleTest::testMissingTokenFailsWithTheLibrarysOwnMessage
Failed asserting that exception of type "InvalidArgumentException" is thrown.
Once the bridge projects are installed (make bridge-install), make test and bin/pre-commit run this suite, so the failure then also blocks commits.
The Laravel suite already handles this (9c5a5d6) and passes with both variables exported. Applying the same setUp()/tearDown() here (clear and restore ZAMMAD_URL/ZAMMAD_TOKEN in $_SERVER, $_ENV and via putenv()) fixes it. The class docblock (line 28, "hermetic and order-independent") needs the same correction.
| ### Laravel | ||
|
|
||
| Supported: **Laravel 12 and 13**. Each of those is exercised in CI — see the | ||
| `unit` job in [`.github/workflows/tests.yml`](.github/workflows/tests.yml). |
There was a problem hiding this comment.
The Laravel legs run in the bridge-laravel job, not unit.
| ### Symfony | ||
|
|
||
| Supported: **Symfony 6.4 LTS, 7.x and 8.x**. Each of those is exercised in CI — | ||
| see the `unit` job in [`.github/workflows/tests.yml`](.github/workflows/tests.yml). |
There was a problem hiding this comment.
Same here: the Symfony legs run in the bridge-symfony job, not unit.
| `GuzzleClientFactory::withToken()` / `withOAuth2()` / `withBasicAuth()` keep their signatures and now delegate to `Auth`. They remain supported shorthand for the explicit-`Auth` constructor and are not scheduled for removal; `ZammadClient::create()` is simply the recommended entry point for new code. | ||
|
|
||
| **One behavioural change to be aware of:** an empty or whitespace-only token (or username) is now rejected with an `InvalidArgumentException` at construction, where it previously produced a client that failed with HTTP 401 on its first request. Code that builds a client from an unset environment variable therefore fails earlier and more clearly than before. Both framework bridges resolve the client lazily, so this surfaces the first time something asks the container for it, not while the container is built: Laravel falls back to an empty token (`env('ZAMMAD_TOKEN', '')`) and throws `InvalidArgumentException`, while the Symfony bundle falls back to `%env(ZAMMAD_TOKEN)%` and throws `EnvNotFoundException` when the variable is unset, or `InvalidArgumentException` when it is set but empty. The Symfony bundle only became lazy in this release — see the fix above; before it, an empty token made `cache:clear` (and with it `composer install`) fail outright. The bundles are still covered by neither tests nor static analysis ([#169](https://github.com/zammad/zammad-api-client-php/issues/169)); the bundle change above was verified by compiling and dumping a container against symfony/dependency-injection 7.4 outside this repository. | ||
| **One behavioural change to be aware of:** an empty or whitespace-only token (or username) is now rejected with an `InvalidArgumentException` at construction, where it previously produced a client that failed with HTTP 401 on its first request. Code that builds a client from an unset environment variable therefore fails earlier and more clearly than before. Both framework bridges resolve the client lazily, so this surfaces the first time something asks the container for it, not while the container is built: Laravel falls back to an empty token (`env('ZAMMAD_TOKEN', '')`) and throws `InvalidArgumentException`, while the Symfony bundle falls back to `%env(ZAMMAD_TOKEN)%` and throws `EnvNotFoundException` when the variable is unset, or `InvalidArgumentException` when it is set but empty. The Symfony bundle only became lazy in this release — see the fix above; before it, an empty token made `cache:clear` (and with it `composer install`) fail outright. The Symfony bundle is now covered by tests and static analysis in this repository, and an unset `ZAMMAD_TOKEN` no longer produces `EnvNotFoundException` — see the entries below ([#169](https://github.com/zammad/zammad-api-client-php/issues/169)). |
There was a problem hiding this comment.
This paragraph first says the Symfony bundle throws EnvNotFoundException for an unset ZAMMAD_TOKEN, then says it no longer does, "see the entries below". Those entries are above (the SymfonyBundle fix and the bridge test entry). Both changes ship in the same unreleased 3.2.0, so the intermediate behaviour is never visible to a user.
Suggested replacement for the Symfony part:
…while the Symfony bundle falls back to an empty token and throws
InvalidArgumentException— unlessconfig/packages/zammad.yamlsetstoken: '%env(ZAMMAD_TOKEN)%'explicitly, in which case Symfony raisesEnvNotFoundExceptionfor an unset variable.
The trailing "and an unset ZAMMAD_TOKEN no longer produces EnvNotFoundException — see the entries below" can then be dropped.
| resolving `ZammadClient` then throws | ||
| `InvalidArgumentException: API token must not be empty.` | ||
|
|
||
| For older Laravel versions, register `ZammadAPIClient\Bridge\LaravelServiceProvider::class` |
There was a problem hiding this comment.
Nit: "For older Laravel versions" and "auto-discovered (Laravel 5.5+)" (line 438) now sit right below "Supported: Laravel 12 and 13". Both could go, or be reworded so they don't read as supported versions.
dvuckovic
left a comment
There was a problem hiding this comment.
@derpixler Looks good overall: the mergeConfigFrom fix for config:cache, the empty-token default in the Symfony bundle and the wider catch in Cast all hold up. Inline comments below: three medium (Symfony test isolation, a swallowed config error in the Laravel provider, a self-contradicting CHANGELOG paragraph) and three low (README/CHANGELOG accuracy, script parity, a CI detail).
Not verified: whether the CI matrix resolves and passes (I couldn't run Composer), and the advisory ID cited in the Laravel matrix comment. That comment is also ambiguous about whether "11.x" means Laravel or PHPUnit.
| */ | ||
| private static function setting(mixed $value, string $default): string | ||
| { | ||
| return is_string($value) && $value !== '' ? $value : $default; |
There was a problem hiding this comment.
Medium: a wrong-typed url silently becomes localhost. The docblock says this narrowing exists so a bad config value doesn't produce an error pointing at the client instead of config/zammad.php. But a non-string value never produces an error at all:
- A non-string
url(an array, an int, a wrongenv()cast) becomeshttp://127.0.0.1:8098without any error, and the client talks to localhost in production. - A non-string
tokenraises "API token must not be empty.", which is misleading when the token is set but has the wrong type.
testNonStringConfigValueDoesNotReachTheClientAsTypeError locks the silent fallback in. Suggest failing with a message that names the key:
private static function setting(string $key, mixed $value, string $default): string
{
if ($value === null || $value === '') {
return $default;
}
if (!is_string($value)) {
throw new InvalidArgumentException(sprintf(
'config/zammad.php: "%s" must be a string, %s given.',
$key,
get_debug_type($value),
));
}
return $value;
}| "composer install -d test/Bridge/Symfony --no-interaction", | ||
| "composer install -d test/Bridge/Laravel --no-interaction" | ||
| ], | ||
| "test:bridge": [ |
There was a problem hiding this comment.
Low: the bridge commands disagree. composer test:bridge runs only PHPUnit, while make test-bridge and bin/pre-commit also run PHPStan. Suggest adding the two PHPStan calls here, or pointing this script at make test-bridge, so there's one definition of "bridge checks".
| extensions: xdebug | ||
| - run: composer install --no-interaction | ||
| - run: composer dump-autoload | ||
| - run: composer update --no-interaction |
There was a problem hiding this comment.
Low: composer install became composer update. Without a committed root lock this behaves the same, but it's an unexplained change now that the job runs on three PHP versions. Separately, the CHANGELOG entry says CI covers "Symfony 6.4, 7.4 and 8.x", but the matrix also has a ~7.0.0 leg, and the README says "7.x".
Summary by CodeRabbit
nullon PHP 8.1 and 8.2.