Skip to content

Commit

Permalink
Configure mockclient if mock_response_factory has been set on a scope…
Browse files Browse the repository at this point in the history
…d client.

This makes it possible to use different mock response factories on different services and also to easily test services that uses http client endpoints.

It also generates an extra test service http_client.mock_client.$name that can be used to configure the MockHttpClient instance if you want to inject a different responsefactory.

We also change the framework.http_client.mock_client_factory attribute to allow for a boolean
so you can just mock without injecting a responsefactory in the service setup.
  • Loading branch information
tarjei committed Apr 12, 2024
1 parent 9b323c6 commit 0e53491
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ CHANGELOG
6.4
---

* Add support for setting mock_response_factory per scoped http client
* Add `HttpClientAssertionsTrait`
* Add `AbstractController::renderBlock()` and `renderBlockView()`
* Add native return type to `Translator` and to `Application::reset()`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1867,7 +1867,7 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->end()
->end()
->scalarNode('mock_response_factory')
->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable.')
->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable or a boolean to just inject the mock client.')
->end()
->arrayNode('scoped_clients')
->useAttributeAsKey('name')
Expand Down Expand Up @@ -2006,6 +2006,9 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e
->variableNode('md5')->end()
->end()
->end()
->scalarNode('mock_response_factory')
->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable or a boolean to just inject the mock client.')
->end()
->arrayNode('extra')
->info('Extra options for specific HTTP client')
->normalizeKeys(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2468,18 +2468,30 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
$retryOptions = $scopeConfig['retry_failed'] ?? ['enabled' => false];
unset($scopeConfig['retry_failed']);


$httpClientTransport = new Reference('http_client.transport');

if ($responseFactoryId = $scopeConfig['mock_response_factory'] ?? null) {


$container->register('http_client.mock_client.' . $name, MockHttpClient::class)
->setDecoratedService($httpClientTransport, null, -10) // lower priority than TraceableHttpClient (5)
->setArguments(
$responseFactoryId === true ? [] : [new Reference($responseFactoryId)]);
}

if (null === $scope) {
$baseUri = $scopeConfig['base_uri'];
unset($scopeConfig['base_uri']);

$container->register($name, ScopingHttpClient::class)
->setFactory([ScopingHttpClient::class, 'forBaseUri'])
->setArguments([new Reference('http_client.transport'), $baseUri, $scopeConfig])
->setArguments([$httpClientTransport, $baseUri, $scopeConfig])
->addTag('http_client.client')
;
} else {
$container->register($name, ScopingHttpClient::class)
->setArguments([new Reference('http_client.transport'), [$scope => $scopeConfig], $scope])
->setArguments([$httpClientTransport, [$scope => $scopeConfig], $scope])
->addTag('http_client.client')
;
}
Expand Down Expand Up @@ -2521,7 +2533,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder
if ($responseFactoryId = $config['mock_response_factory'] ?? null) {
$container->register('http_client.mock_client', MockHttpClient::class)
->setDecoratedService('http_client.transport', null, -10) // lower priority than TraceableHttpClient (5)
->setArguments([new Reference($responseFactoryId)]);
->setArguments($responseFactoryId === true ? [] : [new Reference($responseFactoryId)]);;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@
<xsd:attribute name="local-pk" type="xsd:string" />
<xsd:attribute name="passphrase" type="xsd:string" />
<xsd:attribute name="ciphers" type="xsd:string" />
<xsd:attribute name="mock_response_factory" type="xsd:string" />
<xsd:attribute name="rate-limiter" type="xsd:string" />
</xsd:complexType>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
'php_errors' => ['log' => true],
'http_client' => [
'default_options' => null,
'mock_response_factory' => 'my_response_factory',
'mock_response_factory' => true,
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

$container->loadFromExtension('framework', [
'annotations' => false,
'http_method_override' => false,
'handle_all_throwables' => true,
'php_errors' => ['log' => true],
'http_client' => [
'default_options' => null,
'mock_response_factory' => 'my_response_factory',
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

$container->loadFromExtension('framework', [
'annotations' => false,
'http_method_override' => false,
'handle_all_throwables' => true,
'php_errors' => ['log' => true],
'http_client' => [
'default_options' => null,
'scoped_clients' => [
'notMocked' => [
'base_uri' => 'https://symfony.com'
],
'mocked' => [
'base_uri' => 'https://symfony.com',
'mock_response_factory' => true,
],
]
],
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

$container->loadFromExtension('framework', [
'annotations' => false,
'http_method_override' => false,
'handle_all_throwables' => true,
'php_errors' => ['log' => true],
'http_client' => [
'default_options' => null,
'scoped_clients' => [
'notMocked' => [
'base_uri' => 'https://symfony.com'
],
'mocked' => [
'base_uri' => 'https://symfony.com',
'mock_response_factory' => 'my_response_factory'
],
]
],
]);
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<framework:config http-method-override="false" handle-all-throwables="true">
<framework:annotations enabled="false" />
<framework:php-errors log="true" />
<framework:http-client mock-response-factory="my_response_factory">
<framework:http-client mock-response-factory="true">
<framework:default-options />
</framework:http-client>
</framework:config>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config http-method-override="false" handle-all-throwables="true">
<framework:annotations enabled="false" />
<framework:php-errors log="true" />
<framework:http-client mock-response-factory="my_response_factory">
<framework:default-options />
</framework:http-client>
</framework:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">

<framework:config http-method-override="false" handle-all-throwables="true">
<framework:annotations enabled="false" />
<framework:php-errors log="true" />
<framework:http-client mock-response-factory="my_response_factory">
<framework:default-options />
<framework:scoped-client name="notMocked" base-uri="https://symfony.com" />
<framework:scoped-client name="mocked" base-uri="https://symfony.com" mock_response_factory="true" />
</framework:http-client>
</framework:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
<framework:config http-method-override="false" handle-all-throwables="true">
<framework:annotations enabled="false" />
<framework:php-errors log="true" />
<framework:http-client mock-response-factory="my_response_factory">
<framework:default-options />
<framework:scoped-client name="notMocked" base-uri="https://symfony.com" />
<framework:scoped-client name="mocked" base-uri="https://symfony.com" mock_response_factory="my_response_factory" />
</framework:http-client>
</framework:config>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ framework:
log: true
http_client:
default_options: ~
mock_response_factory: my_response_factory
mock_response_factory: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
framework:
annotations: false
http_method_override: false
handle_all_throwables: true
php_errors:
log: true
http_client:
default_options: ~
mock_response_factory: my_response_factory
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
framework:
annotations: false
http_method_override: false
handle_all_throwables: true
php_errors:
log: true
http_client:
default_options: ~
mock_response_factory: ~

scoped_clients:
notMocked:
base_uri: https://symfony.com
mocked:
base_uri: https://symfony.com
mock_response_factory: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
framework:
annotations: false
http_method_override: false
handle_all_throwables: true
php_errors:
log: true
http_client:
default_options: ~
mock_response_factory: ~

scoped_clients:
notMocked:
base_uri: https://symfony.com
mocked:
base_uri: https://symfony.com
mock_response_factory: "my_response_factory"
Original file line number Diff line number Diff line change
Expand Up @@ -2095,9 +2095,39 @@ public function testMailerWithSpecificMessageBus()
$this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('mailer.mailer')->getArgument(1));
}

public function testHttpClientMockResponseFactory()
public function testHttpClientMockResponseFactoryNoService()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory');
$container = $this->createContainerFromFile('http_client_scoped_mock_response_factory');

$this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked'));

$definition = $container->getDefinition('http_client.mock_client.mocked');

$this->assertSame(MockHttpClient::class, $definition->getClass());
$this->assertCount(0, $definition->getArguments());

}

public function testHttpClientMockResponseFactoryWithService()
{
$container = $this->createContainerFromFile('http_client_scoped_mock_response_factory_service');
$this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked'));

$definition = $container->getDefinition('http_client.mock_client.mocked');

$this->assertSame(MockHttpClient::class, $definition->getClass());
$this->assertCount(1, $definition->getArguments());

$argument = $definition->getArgument(0);

$this->assertInstanceOf(Reference::class, $argument);
$this->assertSame('http_client.transport', current($definition->getDecoratedService()));
$this->assertSame('my_response_factory', (string) $argument);
}

public function testHttpClientMockResponseFactoryService()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory_service');

$definition = $container->getDefinition('http_client.mock_client');

Expand All @@ -2111,6 +2141,17 @@ public function testHttpClientMockResponseFactory()
$this->assertSame('my_response_factory', (string) $argument);
}

public function testHttpClientUseMockResponseFactory()
{
$container = $this->createContainerFromFile('http_client_mock_response_factory');

$definition = $container->getDefinition('http_client.mock_client');

$this->assertSame(MockHttpClient::class, $definition->getClass());
$this->assertCount(0, $definition->getArguments());

}

public function testRegisterParameterCollectingBehaviorDescribingTags()
{
$container = $this->createContainerFromFile('default_config');
Expand Down

0 comments on commit 0e53491

Please sign in to comment.