Skip to content

Commit 65e4475

Browse files
committed
[Messenger] show scheme in exception message when no transport found matching DSN
Improves the exception message thrown when no transport supports a given messenger DSN by showing hinting the scheme that was used - if it can be parsed.
1 parent 6c44684 commit 65e4475

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
16+
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
17+
use Symfony\Component\Messenger\Transport\TransportFactory;
18+
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
19+
use Symfony\Component\Messenger\Transport\TransportInterface;
20+
21+
class TransportFactoryTest extends TestCase
22+
{
23+
/**
24+
* @dataProvider provideThrowsExceptionOnUnsupportedTransport
25+
*/
26+
public function testThrowsExceptionOnUnsupportedTransport(array $transportSupport, string $dsn, ?string $expectedMessage)
27+
{
28+
if (null !== $expectedMessage) {
29+
$this->expectException(InvalidArgumentException::class);
30+
$this->expectExceptionMessage($expectedMessage);
31+
}
32+
$serializer = $this->createMock(SerializerInterface::class);
33+
$factories = [];
34+
foreach ($transportSupport as $supported) {
35+
$factory = $this->createMock(TransportFactoryInterface::class);
36+
$factory->method('supports', $dsn, [])->willReturn($supported);
37+
$factories[] = $factory;
38+
}
39+
40+
$factory = new TransportFactory($factories);
41+
$transport = $factory->createTransport($dsn, [], $serializer);
42+
43+
if (null !== $expectedMessage) {
44+
return;
45+
}
46+
47+
self::assertInstanceOf(TransportInterface::class, $transport);
48+
}
49+
50+
public function provideThrowsExceptionOnUnsupportedTransport(): \Generator
51+
{
52+
yield 'transport supports dsn' => [
53+
[true],
54+
'foobar://barfoo',
55+
null,
56+
];
57+
yield 'show dsn when no transport supports' => [
58+
[false],
59+
'foobar://barfoo',
60+
'No transport supports Messenger DSN "foobar://barfoo".',
61+
];
62+
yield 'empty dsn' => [
63+
[false],
64+
'',
65+
'No transport supports the given Messenger DSN.',
66+
];
67+
yield 'dsn with no scheme' => [
68+
[false],
69+
'barfoo@bar',
70+
'No transport supports Messenger DSN "barfoo@bar".',
71+
];
72+
yield 'dsn with empty scheme ' => [
73+
[false],
74+
'://barfoo@bar',
75+
'No transport supports Messenger DSN "://barfoo@bar".',
76+
];
77+
yield 'https dsn' => [
78+
[false],
79+
'https://sqs.foobar.amazonaws.com',
80+
'No transport supports Messenger DSN "https://sqs.foobar.amazonaws.com"',
81+
];
82+
yield 'with package suggestion amqp://' => [
83+
[false],
84+
'amqp://foo:barfoo@bar',
85+
'No transport supports Messenger DSN "amqp://foo:******@bar". Run "composer require symfony/amqp-messenger" to install AMQP transport.',
86+
];
87+
yield 'replaces password with stars' => [
88+
[false],
89+
'amqp://myuser:mypassword@broker:5672/vhost',
90+
'No transport supports Messenger DSN "amqp://myuser:******@broker:5672/vhost". Run "composer require symfony/amqp-messenger" to install AMQP transport.',
91+
];
92+
yield 'username only is blanked out (as this could be a secret token)' => [
93+
[false],
94+
'amqp://myuser@broker:5672/vhost',
95+
'No transport supports Messenger DSN "amqp://******@broker:5672/vhost". Run "composer require symfony/amqp-messenger" to install AMQP transport.',
96+
];
97+
yield 'empty password' => [
98+
[false],
99+
'amqp://myuser:@broker:5672/vhost',
100+
'No transport supports Messenger DSN "amqp://myuser:******@broker:5672/vhost". Run "composer require symfony/amqp-messenger" to install AMQP transport.',
101+
];
102+
}
103+
}

src/Symfony/Component/Messenger/Transport/TransportFactory.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public function createTransport(#[\SensitiveParameter] string $dsn, array $optio
5353
$packageSuggestion = ' Run "composer require symfony/beanstalkd-messenger" to install Beanstalkd transport.';
5454
}
5555

56+
$scheme = $this->santitizeDsn($dsn);
57+
if ($scheme) {
58+
throw new InvalidArgumentException(\sprintf('No transport supports Messenger DSN "%s".', $scheme).$packageSuggestion);
59+
}
60+
5661
throw new InvalidArgumentException('No transport supports the given Messenger DSN.'.$packageSuggestion);
5762
}
5863

@@ -66,4 +71,41 @@ public function supports(#[\SensitiveParameter] string $dsn, array $options): bo
6671

6772
return false;
6873
}
74+
75+
private function santitizeDsn(string $dsn): ?string
76+
{
77+
$parts = parse_url($dsn);
78+
$dsn = '';
79+
80+
if (isset($parts['scheme'])) {
81+
$dsn .= $parts['scheme'].'://';
82+
}
83+
84+
if (isset($parts['user']) && !isset($parts['pass'])) {
85+
$dsn .= '******';
86+
} elseif (isset($parts['user'])) {
87+
$dsn .= $parts['user'];
88+
}
89+
90+
if (isset($parts['pass'])) {
91+
$dsn .= ':******';
92+
}
93+
94+
if (isset($parts['host'])) {
95+
if (isset($parts['user'])) {
96+
$dsn .= '@';
97+
}
98+
$dsn .= $parts['host'];
99+
}
100+
101+
if (isset($parts['port'])) {
102+
$dsn .= ':'.$parts['port'];
103+
}
104+
105+
if (isset($parts['path'])) {
106+
$dsn .= $parts['path'];
107+
}
108+
109+
return $dsn;
110+
}
69111
}

0 commit comments

Comments
 (0)