Skip to content

Commit de3ce3f

Browse files
committed
[gps] enhance connection configuration.
1 parent 0282a6c commit de3ce3f

File tree

3 files changed

+158
-20
lines changed

3 files changed

+158
-20
lines changed

Diff for: pkg/gps/GpsConnectionFactory.php

+47-12
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Enqueue\Gps;
66

7+
use Enqueue\Dsn\Dsn;
78
use Google\Cloud\PubSub\PubSubClient;
89
use Interop\Queue\PsrConnectionFactory;
910
use Interop\Queue\PsrContext;
@@ -15,6 +16,11 @@ class GpsConnectionFactory implements PsrConnectionFactory
1516
*/
1617
private $config;
1718

19+
/**
20+
* @var PubSubClient
21+
*/
22+
private $client;
23+
1824
/**
1925
* @see https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
2026
* @see \Google\Cloud\PubSub\PubSubClient::__construct()
@@ -24,6 +30,7 @@ class GpsConnectionFactory implements PsrConnectionFactory
2430
* 'keyFilePath' => The full path to your service account credentials.json file retrieved from the Google Developers Console.
2531
* 'retries' => Number of retries for a failed request. **Defaults to** `3`.
2632
* 'scopes' => Scopes to be used for the request.
33+
* 'emulatorHost' => The endpoint used to emulate communication with GooglePubSub.
2734
* 'lazy' => 'the connection will be performed as later as possible, if the option set to true'
2835
* ]
2936
*
@@ -32,17 +39,31 @@ class GpsConnectionFactory implements PsrConnectionFactory
3239
* gps:
3340
* gps:?projectId=projectName
3441
*
35-
* @param array|string|null $config
42+
* or instance of Google\Cloud\PubSub\PubSubClient
43+
*
44+
* @param array|string|PubSubClient|null $config
3645
*/
3746
public function __construct($config = 'gps:')
3847
{
39-
if (empty($config) || 'gps:' === $config) {
48+
if ($config instanceof PubSubClient) {
49+
$this->client = $config;
50+
$this->config = ['lazy' => false] + $this->defaultConfig();
51+
52+
return;
53+
}
54+
55+
if (empty($config)) {
4056
$config = [];
4157
} elseif (is_string($config)) {
4258
$config = $this->parseDsn($config);
4359
} elseif (is_array($config)) {
60+
if (array_key_exists('dsn', $config)) {
61+
$config = array_replace_recursive($config, $this->parseDsn($config['dsn']));
62+
63+
unset($config['dsn']);
64+
}
4465
} else {
45-
throw new \LogicException('The config must be either an array of options, a DSN string or null');
66+
throw new \LogicException(sprintf('The config must be either an array of options, a DSN string, null or instance of %s', PubSubClient::class));
4667
}
4768

4869
$this->config = array_replace($this->defaultConfig(), $config);
@@ -64,22 +85,36 @@ public function createContext(): PsrContext
6485

6586
private function parseDsn(string $dsn): array
6687
{
67-
if (false === strpos($dsn, 'gps:')) {
68-
throw new \LogicException(sprintf('The given DSN "%s" is not supported. Must start with "gps:".', $dsn));
69-
}
70-
71-
$config = [];
88+
$dsn = new Dsn($dsn);
7289

73-
if ($query = parse_url($dsn, PHP_URL_QUERY)) {
74-
parse_str($query, $config);
90+
if ('gps' !== $dsn->getSchemeProtocol()) {
91+
throw new \LogicException(sprintf(
92+
'The given scheme protocol "%s" is not supported. It must be "gps"',
93+
$dsn->getSchemeProtocol()
94+
));
7595
}
7696

77-
return $config;
97+
$emulatorHost = $dsn->getQueryParameter('emulatorHost');
98+
$hasEmulator = $emulatorHost ? true : null;
99+
100+
return array_filter(array_replace($dsn->getQuery(), [
101+
'projectId' => $dsn->getQueryParameter('projectId'),
102+
'keyFilePath' => $dsn->getQueryParameter('keyFilePath'),
103+
'retries' => $dsn->getInt('retries'),
104+
'scopes' => $dsn->getQueryParameter('scopes'),
105+
'emulatorHost' => $emulatorHost,
106+
'hasEmulator' => $hasEmulator,
107+
'lazy' => $dsn->getBool('lazy'),
108+
]), function ($value) { return null !== $value; });
78109
}
79110

80111
private function establishConnection(): PubSubClient
81112
{
82-
return new PubSubClient($this->config);
113+
if (false == $this->client) {
114+
$this->client = new PubSubClient($this->config);
115+
}
116+
117+
return $this->client;
83118
}
84119

85120
private function defaultConfig(): array

Diff for: pkg/gps/Tests/GpsConnectionFactoryConfigTest.php

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
3+
namespace Enqueue\Gps\Tests;
4+
5+
use Enqueue\Gps\GpsConnectionFactory;
6+
use Enqueue\Test\ClassExtensionTrait;
7+
use PHPUnit\Framework\TestCase;
8+
9+
/**
10+
* The class contains the factory tests dedicated to configuration.
11+
*/
12+
class GpsConnectionFactoryConfigTest extends TestCase
13+
{
14+
use ClassExtensionTrait;
15+
16+
public function testThrowNeitherArrayStringNorNullGivenAsConfig()
17+
{
18+
$this->expectException(\LogicException::class);
19+
$this->expectExceptionMessage('The config must be either an array of options, a DSN string, null or instance of Google\Cloud\PubSub\PubSubClient');
20+
21+
new GpsConnectionFactory(new \stdClass());
22+
}
23+
24+
public function testThrowIfSchemeIsNotAmqp()
25+
{
26+
$this->expectException(\LogicException::class);
27+
$this->expectExceptionMessage('The given scheme protocol "http" is not supported. It must be "gps"');
28+
29+
new GpsConnectionFactory('http://example.com');
30+
}
31+
32+
public function testThrowIfDsnCouldNotBeParsed()
33+
{
34+
$this->expectException(\LogicException::class);
35+
$this->expectExceptionMessage('The DSN is invalid.');
36+
37+
new GpsConnectionFactory('foo');
38+
}
39+
40+
/**
41+
* @dataProvider provideConfigs
42+
*
43+
* @param mixed $config
44+
* @param mixed $expectedConfig
45+
*/
46+
public function testShouldParseConfigurationAsExpected($config, $expectedConfig)
47+
{
48+
$factory = new GpsConnectionFactory($config);
49+
50+
$this->assertAttributeEquals($expectedConfig, 'config', $factory);
51+
}
52+
53+
public static function provideConfigs()
54+
{
55+
yield [
56+
null,
57+
[
58+
'lazy' => true,
59+
],
60+
];
61+
62+
yield [
63+
'gps:',
64+
[
65+
'lazy' => true,
66+
],
67+
];
68+
69+
yield [
70+
[],
71+
[
72+
'lazy' => true,
73+
],
74+
];
75+
76+
yield [
77+
'gps:?foo=fooVal&projectId=mqdev&emulatorHost=http%3A%2F%2Fgoogle-pubsub%3A8085',
78+
[
79+
'foo' => 'fooVal',
80+
'projectId' => 'mqdev',
81+
'emulatorHost' => 'http://google-pubsub:8085',
82+
'hasEmulator' => true,
83+
'lazy' => true,
84+
],
85+
];
86+
87+
yield [
88+
['dsn' => 'gps:?foo=fooVal&projectId=mqdev&emulatorHost=http%3A%2F%2Fgoogle-pubsub%3A8085'],
89+
[
90+
'foo' => 'fooVal',
91+
'projectId' => 'mqdev',
92+
'emulatorHost' => 'http://google-pubsub:8085',
93+
'hasEmulator' => true,
94+
'lazy' => true,
95+
],
96+
];
97+
98+
yield [
99+
['foo' => 'fooVal', 'projectId' => 'mqdev', 'emulatorHost' => 'http://Fgoogle-pubsub:8085', 'lazy' => false],
100+
[
101+
'foo' => 'fooVal',
102+
'projectId' => 'mqdev',
103+
'emulatorHost' => 'http://Fgoogle-pubsub:8085',
104+
'lazy' => false,
105+
],
106+
];
107+
}
108+
}

Diff for: pkg/gps/composer.json

+3-8
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,13 @@
88
"require": {
99
"php": "^7.1.3",
1010
"queue-interop/queue-interop": "0.7.x-dev",
11-
"google/cloud-pubsub": "^0.6.1|^1.0"
11+
"google/cloud-pubsub": "^1.0",
12+
"enqueue/dsn": "0.9.x-dev"
1213
},
1314
"require-dev": {
1415
"phpunit/phpunit": "~5.4.0",
1516
"enqueue/test": "0.9.x-dev",
16-
"enqueue/enqueue": "0.9.x-dev",
17-
"queue-interop/queue-spec": "0.6.x-dev",
18-
"symfony/dependency-injection": "^3.4|^4",
19-
"symfony/config": "^3.4|^4"
17+
"queue-interop/queue-spec": "0.6.x-dev"
2018
},
2119
"support": {
2220
"email": "opensource@forma-pro.com",
@@ -31,9 +29,6 @@
3129
"/Tests/"
3230
]
3331
},
34-
"suggest": {
35-
"enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features"
36-
},
3732
"minimum-stability": "dev",
3833
"extra": {
3934
"branch-alias": {

0 commit comments

Comments
 (0)