From 5fd1b3212885808b3ebdc71810d92581ec798d3c Mon Sep 17 00:00:00 2001 From: Tarjei Huse Date: Tue, 24 Oct 2023 12:14:01 +0200 Subject: [PATCH 1/4] Configure mockclient if mock_response_factory has been set on a scoped 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. --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../DependencyInjection/Configuration.php | 5 ++- .../FrameworkExtension.php | 15 +++++-- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../php/http_client_mock_response_factory.php | 2 +- ...p_client_mock_response_factory_service.php | 12 ++++++ ...tp_client_scoped_mock_response_factory.php | 20 +++++++++ ...t_scoped_mock_response_factory_service.php | 20 +++++++++ .../xml/http_client_mock_response_factory.xml | 2 +- ...p_client_mock_response_factory_service.xml | 15 +++++++ ...tp_client_scoped_mock_response_factory.xml | 17 ++++++++ ...t_scoped_mock_response_factory_service.xml | 16 +++++++ .../yml/http_client_mock_response_factory.yml | 2 +- ...p_client_mock_response_factory_service.yml | 9 ++++ ...tp_client_scoped_mock_response_factory.yml | 16 +++++++ ...t_scoped_mock_response_factory_service.yml | 16 +++++++ .../FrameworkExtensionTestCase.php | 43 ++++++++++++++++++- 17 files changed, 203 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index df0d692ebdf7a..3355a0f52824c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -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()` diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 92c20d139da6e..29becf671d19e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -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') @@ -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) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 86355e5ca1e93..a76d3c5fc4157 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2468,18 +2468,27 @@ 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( + true === $responseFactoryId ? [] : [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') ; } @@ -2521,7 +2530,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(true === $responseFactoryId ? [] : [new Reference($responseFactoryId)]); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index d8d23168d1887..98392c6c2e187 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -697,6 +697,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php index 326f0d25db503..c0b9cf5ef7f6f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php @@ -7,6 +7,6 @@ 'php_errors' => ['log' => true], 'http_client' => [ 'default_options' => null, - 'mock_response_factory' => 'my_response_factory', + 'mock_response_factory' => true, ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php new file mode 100644 index 0000000000000..326f0d25db503 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php @@ -0,0 +1,12 @@ +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', + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php new file mode 100644 index 0000000000000..dbba92de997f5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php @@ -0,0 +1,20 @@ +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, + ], + ] + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php new file mode 100644 index 0000000000000..dcbd1cb0e76d6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php @@ -0,0 +1,20 @@ +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' + ], + ] + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml index d2bc058fb17ea..c5238a5d922f2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml @@ -8,7 +8,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml new file mode 100644 index 0000000000000..d2bc058fb17ea --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml new file mode 100644 index 0000000000000..b4b64ffb54962 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml new file mode 100644 index 0000000000000..7d2f04a21ae07 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml index 92c40b4591b1f..a10995312c9d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml @@ -6,4 +6,4 @@ framework: log: true http_client: default_options: ~ - mock_response_factory: my_response_factory + mock_response_factory: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml new file mode 100644 index 0000000000000..92c40b4591b1f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml @@ -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 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml new file mode 100644 index 0000000000000..c8c74e103be05 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory.yml @@ -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 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml new file mode 100644 index 0000000000000..b0a1500b0e5b5 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_scoped_mock_response_factory_service.yml @@ -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" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index 2a26e786b436a..fc5a0baefbd42 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -2095,9 +2095,38 @@ 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'); @@ -2111,6 +2140,16 @@ 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'); From 8b433952c2ea9b691b8a77924427d6c8d29f93a4 Mon Sep 17 00:00:00 2001 From: Tarjei Huse Date: Fri, 10 May 2024 12:10:04 +0200 Subject: [PATCH 2/4] Improve testcoverage and add mock_client boolean parameter. Also: If you mock the default client then this choice becomes the default for scoped clients --- .../DependencyInjection/Configuration.php | 11 ++++- .../FrameworkExtension.php | 22 +++++---- .../Resources/config/schema/symfony-1.0.xsd | 4 +- ...ctory_service.php => http_client_mock.php} | 10 +++- .../php/http_client_mock_response_factory.php | 16 ++++++- ...p_client_mock_response_factory_service.php | 12 ----- ...tp_client_scoped_mock_response_factory.php | 20 -------- ...ponse_factory.xml => http_client_mock.xml} | 7 +-- .../xml/http_client_mock_response_factory.xml | 6 ++- ...p_client_mock_response_factory_service.xml | 15 ------ ...t_scoped_mock_response_factory_service.xml | 16 ------- .../Fixtures/yml/http_client_mock.yml | 18 ++++++++ .../yml/http_client_mock_response_factory.yml | 12 ++++- ...p_client_mock_response_factory_service.yml | 9 ---- .../FrameworkExtensionTestCase.php | 46 ++++++++++--------- 15 files changed, 112 insertions(+), 112 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{http_client_scoped_mock_response_factory_service.php => http_client_mock.php} (74%) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{http_client_scoped_mock_response_factory.xml => http_client_mock.xml} (76%) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 29becf671d19e..2a130706a2972 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1866,8 +1866,12 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->append($this->createHttpClientRetrySection()) ->end() ->end() + ->booleanNode('mock_client') + ->info('Inject a mock client.') + ->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.') + ->defaultNull() + ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true') ->end() ->arrayNode('scoped_clients') ->useAttributeAsKey('name') @@ -2006,8 +2010,11 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->variableNode('md5')->end() ->end() ->end() + ->booleanNode('mock_client') + ->info('Inject a mock client.') + ->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.') + ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable') ->end() ->arrayNode('extra') ->info('Extra options for specific HTTP client') diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a76d3c5fc4157..0a6f509aa5d14 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2456,6 +2456,14 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder ->getDefinition('http_client.uri_template') ->setArgument(2, $defaultUriTemplateVars); + $mockByDefault = $config['mock_client'] ?? false; + $defaultMockResponseFactory = $config['mock_response_factory'] ?? null; + if ($mockByDefault) { + $container->register('http_client.mock_client', MockHttpClient::class) + ->setDecoratedService('http_client.transport', null, -10) // lower priority than TraceableHttpClient (5) + ->setArguments($defaultMockResponseFactory === null ? [] : [new Reference($defaultMockResponseFactory)]); + } + foreach ($config['scoped_clients'] as $name => $scopeConfig) { if ($container->has($name)) { throw new InvalidArgumentException(sprintf('Invalid scope name: "%s" is reserved.', $name)); @@ -2470,11 +2478,12 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder $httpClientTransport = new Reference('http_client.transport'); - if ($responseFactoryId = $scopeConfig['mock_response_factory'] ?? null) { + if ($scopeConfig['mock_client'] ?? $mockByDefault) { + $mockResponseFactory = $scopeConfig['mock_response_factory'] ?? $defaultMockResponseFactory; + $mockClientArguments = ($mockResponseFactory) ? [new Reference($mockResponseFactory)]: []; $container->register('http_client.mock_client.'.$name, MockHttpClient::class) ->setDecoratedService($httpClientTransport, null, -10) // lower priority than TraceableHttpClient (5) - ->setArguments( - true === $responseFactoryId ? [] : [new Reference($responseFactoryId)]); + ->setArguments($mockClientArguments); } if (null === $scope) { @@ -2510,6 +2519,7 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder $defaultUriTemplateVars, ]); + $container->registerAliasForArgument($name, HttpClientInterface::class); if ($hasPsr18) { @@ -2527,11 +2537,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(true === $responseFactoryId ? [] : [new Reference($responseFactoryId)]); - } + } private function registerThrottlingHttpClient(string $rateLimiter, string $name, ContainerBuilder $container): void diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 98392c6c2e187..fe856463e1187 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -640,6 +640,7 @@ + @@ -697,7 +698,8 @@ - + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php similarity index 74% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php index dcbd1cb0e76d6..0496fd4e21bf0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory_service.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock.php @@ -1,4 +1,4 @@ -loadFromExtension('framework', [ 'annotations' => false, @@ -7,14 +7,20 @@ 'php_errors' => ['log' => true], 'http_client' => [ 'default_options' => null, + 'mock_client' => true, 'scoped_clients' => [ 'notMocked' => [ - 'base_uri' => 'https://symfony.com' + 'base_uri' => 'https://symfony.com', + 'mock_client' => false, ], 'mocked' => [ + 'base_uri' => 'https://symfony.com' + ], + 'mocked_with_factory' => [ 'base_uri' => 'https://symfony.com', 'mock_response_factory' => 'my_response_factory' ], + ] ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php index c0b9cf5ef7f6f..57cc4290d2559 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory.php @@ -7,6 +7,20 @@ 'php_errors' => ['log' => true], 'http_client' => [ 'default_options' => null, - 'mock_response_factory' => true, + 'mock_client' => true, + 'mock_response_factory' => 'my_factory', + 'scoped_clients' => [ + 'notMocked' => [ + 'base_uri' => 'https://symfony.com', + 'mock_client' => false, + ], + 'mocked' => [ + 'base_uri' => 'https://symfony.com' + ], + 'mocked_custom_factory' => [ + 'base_uri' => 'https://symfony.com', + 'mock_response_factory' => 'my_other_factory' + ] + ] ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php deleted file mode 100644 index 326f0d25db503..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_mock_response_factory_service.php +++ /dev/null @@ -1,12 +0,0 @@ -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', - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php deleted file mode 100644 index dbba92de997f5..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_scoped_mock_response_factory.php +++ /dev/null @@ -1,20 +0,0 @@ -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, - ], - ] - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml similarity index 76% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml index b4b64ffb54962..0dd3d74ee002f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock.xml @@ -8,10 +8,11 @@ - + - - + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml index c5238a5d922f2..b99a4ed206f36 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory.xml @@ -8,8 +8,12 @@ - + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml deleted file mode 100644 index d2bc058fb17ea..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_mock_response_factory_service.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml deleted file mode 100644 index 7d2f04a21ae07..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_scoped_mock_response_factory_service.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml new file mode 100644 index 0000000000000..a6365674c3487 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock.yml @@ -0,0 +1,18 @@ +framework: + annotations: false + http_method_override: false + handle_all_throwables: true + php_errors: + log: true + http_client: + default_options: ~ + mock_client: true + scoped_clients: + notMocked: + base_uri : https://symfony.com + mock_client : false + mocked: + base_uri: https://symfony.com + mocked_with_factory: + base_uri: https://symfony.com + mock_response_factory: 'my_response_factory' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml index a10995312c9d5..6283b80d26fc1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory.yml @@ -6,4 +6,14 @@ framework: log: true http_client: default_options: ~ - mock_response_factory: true + mock_client: true + mock_response_factory: 'my_factory' + scoped_clients: + notMocked: + base_uri : https://symfony.com + mock_client : false + mocked: + base_uri: https://symfony.com + mocked_custom_factory: + base_uri: https://symfony.com + mock_response_factory: 'my_other_factory' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml deleted file mode 100644 index 92c40b4591b1f..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_mock_response_factory_service.yml +++ /dev/null @@ -1,9 +0,0 @@ -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 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index fc5a0baefbd42..540be789d0bf5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -2095,21 +2095,19 @@ public function testMailerWithSpecificMessageBus() $this->assertEquals(new Reference('app.another_bus'), $container->getDefinition('mailer.mailer')->getArgument(1)); } - public function testHttpClientMockResponseFactoryNoService() + public function testHttpClientNoMock() { - $container = $this->createContainerFromFile('http_client_scoped_mock_response_factory'); - - $this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked')); + $container = $this->createContainerFromFile('http_client_scoped_without_query_option'); - $definition = $container->getDefinition('http_client.mock_client.mocked'); + $this->assertFalse($container->hasDefinition('http_client.mock_client.foo')); + $this->assertFalse($container->hasDefinition('http_client.mock_client')); - $this->assertSame(MockHttpClient::class, $definition->getClass()); - $this->assertCount(0, $definition->getArguments()); } - public function testHttpClientMockResponseFactoryWithService() + public function testHttpClientMockResponseFactory() { - $container = $this->createContainerFromFile('http_client_scoped_mock_response_factory_service'); + $container = $this->createContainerFromFile('http_client_mock_response_factory'); + $this->assertFalse($container->hasDefinition('http_client.mock_client.notMocked')); $definition = $container->getDefinition('http_client.mock_client.mocked'); @@ -2118,36 +2116,42 @@ public function testHttpClientMockResponseFactoryWithService() $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); - } + $this->assertSame('my_factory', (string) $argument); - public function testHttpClientMockResponseFactoryService() - { - $container = $this->createContainerFromFile('http_client_mock_response_factory_service'); - - $definition = $container->getDefinition('http_client.mock_client'); + $definition = $container->getDefinition('http_client.mock_client.mocked_custom_factory'); $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); + $this->assertSame('my_other_factory', (string) $argument); } - public function testHttpClientUseMockResponseFactory() + public function testHttpClientUseMockClientButOverrideInScopedClientsAndEnableFactories() { - $container = $this->createContainerFromFile('http_client_mock_response_factory'); + $container = $this->createContainerFromFile('http_client_mock'); $definition = $container->getDefinition('http_client.mock_client'); $this->assertSame(MockHttpClient::class, $definition->getClass()); $this->assertCount(0, $definition->getArguments()); + + $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()); + + $definition = $container->getDefinition('http_client.mock_client.mocked_with_factory'); + + $this->assertSame(MockHttpClient::class, $definition->getClass()); + $this->assertCount(1, $definition->getArguments()); + } public function testRegisterParameterCollectingBehaviorDescribingTags() From 12fab44c9a8f320947d9c49c708f7017a1e9a6d6 Mon Sep 17 00:00:00 2001 From: Tarjei Huse Date: Fri, 10 May 2024 12:22:20 +0200 Subject: [PATCH 3/4] Fix test --- .../DependencyInjection/Configuration.php | 16 +++++++++------- .../DependencyInjection/ConfigurationTest.php | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 2a130706a2972..29f3b3d305d13 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1864,15 +1864,17 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->info('Rate limiter name to use for throttling requests') ->end() ->append($this->createHttpClientRetrySection()) + ->booleanNode('mock_client') + ->info('Inject a mock client.') + ->defaultFalse() + ->end() + ->scalarNode('mock_response_factory') + ->defaultNull() + ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true') + ->end() ->end() ->end() - ->booleanNode('mock_client') - ->info('Inject a mock client.') - ->end() - ->scalarNode('mock_response_factory') - ->defaultNull() - ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true') - ->end() + ->arrayNode('scoped_clients') ->useAttributeAsKey('name') ->normalizeKeys(false) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index b32d8681b43b3..9a3aee28df4f7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -574,7 +574,7 @@ public function testScopedHttpClientsInheritRateLimiterAndRetryFailedConfigurati $config = $processor->processConfiguration($configuration, [[ 'http_client' => [ - 'default_options' => ['rate_limiter' => 'default_limiter', 'retry_failed' => ['max_retries' => 77]], + 'default_options' => ['rate_limiter' => 'default_limiter', 'retry_failed' => ['max_retries' => 77], 'mock_response_factory' => null, 'mock_client' => false], 'scoped_clients' => [ 'foo' => ['base_uri' => 'http://example.com'], 'bar' => ['base_uri' => 'http://example.com', 'rate_limiter' => true, 'retry_failed' => true], From 776e650e3fc4ea268dde3fcd24017d57e7a97746 Mon Sep 17 00:00:00 2001 From: Tarjei Huse Date: Sun, 12 May 2024 20:21:28 +0200 Subject: [PATCH 4/4] Move mock_ options out of default_options and update tests accordingly --- .../DependencyInjection/Configuration.php | 17 ++++++++--------- .../DependencyInjection/ConfigurationTest.php | 4 +++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 29f3b3d305d13..5011a7ecaaf67 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1864,17 +1864,16 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode, callable $e ->info('Rate limiter name to use for throttling requests') ->end() ->append($this->createHttpClientRetrySection()) - ->booleanNode('mock_client') - ->info('Inject a mock client.') - ->defaultFalse() - ->end() - ->scalarNode('mock_response_factory') - ->defaultNull() - ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true') - ->end() ->end() ->end() - + ->booleanNode('mock_client') + ->info('Inject a mock client.') + ->defaultFalse() + ->end() + ->scalarNode('mock_response_factory') + ->defaultNull() + ->info('The id of the service that should generate mock responses. It should be either an invokable or an iterable. Requires mock_client = true') + ->end() ->arrayNode('scoped_clients') ->useAttributeAsKey('name') ->normalizeKeys(false) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 9a3aee28df4f7..9ac71623c98e9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -574,7 +574,7 @@ public function testScopedHttpClientsInheritRateLimiterAndRetryFailedConfigurati $config = $processor->processConfiguration($configuration, [[ 'http_client' => [ - 'default_options' => ['rate_limiter' => 'default_limiter', 'retry_failed' => ['max_retries' => 77], 'mock_response_factory' => null, 'mock_client' => false], + 'default_options' => ['rate_limiter' => 'default_limiter', 'retry_failed' => ['max_retries' => 77]], 'scoped_clients' => [ 'foo' => ['base_uri' => 'http://example.com'], 'bar' => ['base_uri' => 'http://example.com', 'rate_limiter' => true, 'retry_failed' => true], @@ -808,6 +808,8 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'disallow_search_engine_index' => true, 'http_client' => [ 'enabled' => !class_exists(FullStack::class) && class_exists(HttpClient::class), + 'mock_client' => false, + 'mock_response_factory' => null, 'scoped_clients' => [], ], 'mailer' => [