diff --git a/.travis.yml b/.travis.yml index f358a00cf..ecc11eaf0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,12 @@ matrix: - php: 7.2 sudo: false env: SYMFONY_VERSION=4.0.* UNIT_TESTS=true + - php: 7.3 + sudo: false + env: SYMFONY_VERSION=4.1.* UNIT_TESTS=true + - php: 7.3 + sudo: false + env: SYMFONY_VERSION=4.2.* UNIT_TESTS=true - php: 7.1 services: docker sudo: required diff --git a/composer.json b/composer.json index 639b274b6..cb9751df8 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,6 @@ "ramsey/uuid": "^2|^3.5", "psr/log": "^1", "psr/container": "^1", - "symfony/event-dispatcher": "4.0.*", "makasim/temp-file": "^0.2", "google/cloud-pubsub": "^0.6.1|^1.0", "doctrine/orm": "~2.4", @@ -40,16 +39,16 @@ "phpunit/phpunit": "^5.5", "phpstan/phpstan": "^0.10", "queue-interop/queue-spec": "^0.6", - "symfony/browser-kit": "4.0.*", - "symfony/config": "4.0.*", - "symfony/process": "4.0.*", - "symfony/console": "4.0.*", - "symfony/dependency-injection": "4.0.*", - "symfony/event-dispatcher": "4.0.*", - "symfony/expression-language": "4.0.*", - "symfony/http-kernel": "4.0.*", - "symfony/filesystem": "4.0.*", - "symfony/framework-bundle": "4.0.*", + "symfony/browser-kit": "^3.4|^4", + "symfony/config": "^3.4|^4", + "symfony/process": "^3.4|^4", + "symfony/console": "^3.4|^4", + "symfony/dependency-injection": "^3.4|^4", + "symfony/event-dispatcher": "^3.4|^4", + "symfony/expression-language": "^3.4|^4", + "symfony/http-kernel": "^3.4|^4", + "symfony/filesystem": "^3.4|^4", + "symfony/framework-bundle": "^3.4|^4", "empi89/php-amqp-stubs": "*@dev", "doctrine/doctrine-bundle": "~1.2", "kwn/php-rdkafka-stubs": "^1.0.2", diff --git a/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml index eab956cc4..eda14e00c 100644 --- a/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml +++ b/pkg/enqueue-bundle/Tests/Functional/App/config/custom-config.yml @@ -31,6 +31,10 @@ services: alias: 'enqueue.client.default.producer' public: true + test_enqueue.client.default.lazy_producer: + alias: 'enqueue.client.default.lazy_producer' + public: true + test_enqueue.transport.default.context: alias: 'enqueue.transport.default.context' public: true diff --git a/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php b/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php new file mode 100644 index 000000000..cf9af030e --- /dev/null +++ b/pkg/enqueue-bundle/Tests/Functional/LazyProducerTest.php @@ -0,0 +1,79 @@ +remove(static::$kernel->getLogDir()); + $fs->remove(static::$kernel->getCacheDir()); + } + + parent::tearDown(); + } + + public function testShouldAllowGetLazyProducerWithoutError() + { + $this->customSetUp([ + 'default' => [ + 'transport' => [ + 'dsn' => 'invalidDSN', + ], + ], + ]); + + /** @var LazyProducer $producer */ + $producer = static::$container->get('test_enqueue.client.default.lazy_producer'); + $this->assertInstanceOf(LazyProducer::class, $producer); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The DSN is invalid.'); + $producer->sendEvent('foo', 'foo'); + } + + /** + * @return string + */ + public static function getKernelClass() + { + include_once __DIR__.'/App/CustomAppKernel.php'; + + return CustomAppKernel::class; + } + + protected function customSetUp(array $enqueueConfig) + { + static::$class = null; + + static::$client = static::createClient(['enqueue_config' => $enqueueConfig]); + static::$client->getKernel()->boot(); + static::$kernel = static::$client->getKernel(); + static::$container = static::$kernel->getContainer(); + } + + protected static function createKernel(array $options = []): CustomAppKernel + { + /** @var CustomAppKernel $kernel */ + $kernel = parent::createKernel($options); + + $kernel->setEnqueueConfig(isset($options['enqueue_config']) ? $options['enqueue_config'] : []); + + return $kernel; + } +} diff --git a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php index 0a5f38325..f4f11abb1 100644 --- a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php +++ b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php @@ -372,9 +372,9 @@ protected function customSetUp(array $enqueueConfig) { static::$class = null; - $this->client = static::createClient(['enqueue_config' => $enqueueConfig]); - $this->client->getKernel()->boot(); - static::$kernel = $this->client->getKernel(); + static::$client = static::createClient(['enqueue_config' => $enqueueConfig]); + static::$client->getKernel()->boot(); + static::$kernel = static::$client->getKernel(); static::$container = static::$kernel->getContainer(); /** @var DriverInterface $driver */ diff --git a/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php b/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php index 0cf1a0723..2b4f58173 100644 --- a/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php +++ b/pkg/enqueue-bundle/Tests/Functional/WebTestCase.php @@ -13,7 +13,7 @@ abstract class WebTestCase extends BaseWebTestCase /** * @var Client */ - protected $client; + protected static $client; /** * @var ContainerInterface @@ -25,18 +25,21 @@ protected function setUp() parent::setUp(); static::$class = null; - - $this->client = static::createClient(); - - if (false == static::$container) { - static::$container = static::$kernel->getContainer(); - } + static::$client = static::createClient(); + static::$container = static::$kernel->getContainer(); /** @var TraceableProducer $producer */ $producer = static::$container->get('test_enqueue.client.default.traceable_producer'); $producer->clearTraces(); } + protected function tearDown() + { + static::$client = null; + static::$kernel = null; + static::$container = null; + } + /** * @return string */ diff --git a/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php b/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php index e69311e36..bdae6f3b5 100644 --- a/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php +++ b/pkg/enqueue/Symfony/Client/DependencyInjection/ClientFactory.php @@ -21,12 +21,14 @@ use Enqueue\Consumption\QueueConsumer; use Enqueue\Rpc\RpcFactory; use Enqueue\Symfony\Client\FlushSpoolProducerListener; +use Enqueue\Symfony\Client\LazyProducer; use Enqueue\Symfony\ContainerProcessorRegistry; use Enqueue\Symfony\DependencyInjection\TransportFactory; use Enqueue\Symfony\DiUtils; use Interop\Queue\Context; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Reference; @@ -119,14 +121,21 @@ public function build(ContainerBuilder $container, array $config): void ; $container->register($this->diUtils->format('producer'), Producer::class) + // @deprecated ->setPublic(true) ->addArgument($this->diUtils->reference('driver')) ->addArgument($this->diUtils->reference('rpc_factory')) ->addArgument($this->diUtils->reference('client_extensions')) ; + $lazyProducer = $container->register($this->diUtils->format('lazy_producer'), LazyProducer::class); + $lazyProducer->addArgument(ServiceLocatorTagPass::register($container, [ + $this->diUtils->format('producer') => new Reference($this->diUtils->format('producer')), + ])); + $lazyProducer->addArgument($this->diUtils->format('producer')); + $container->register($this->diUtils->format('spool_producer'), SpoolProducer::class) - ->addArgument($this->diUtils->reference('producer')) + ->addArgument($this->diUtils->reference('lazy_producer')) ; $container->register($this->diUtils->format('client_extensions'), ChainExtension::class) @@ -200,12 +209,12 @@ public function build(ContainerBuilder $container, array $config): void $this->diUtils->format('queue_consumer') => $this->diUtils->reference('queue_consumer'), $this->diUtils->format('driver') => $this->diUtils->reference('driver'), $this->diUtils->format('delegate_processor') => $this->diUtils->reference('delegate_processor'), - $this->diUtils->format('producer') => $this->diUtils->reference('producer'), + $this->diUtils->format('producer') => $this->diUtils->reference('lazy_producer'), ])); } if ($this->default) { - $container->setAlias(ProducerInterface::class, $this->diUtils->format('producer')); + $container->setAlias(ProducerInterface::class, $this->diUtils->format('lazy_producer')); $container->setAlias(SpoolProducer::class, $this->diUtils->format('spool_producer')); if (DiUtils::DEFAULT_CONFIG !== $this->diUtils->getConfigName()) { diff --git a/pkg/enqueue/Symfony/Client/LazyProducer.php b/pkg/enqueue/Symfony/Client/LazyProducer.php new file mode 100644 index 000000000..8dd3aadba --- /dev/null +++ b/pkg/enqueue/Symfony/Client/LazyProducer.php @@ -0,0 +1,37 @@ +container = $container; + $this->producerId = $producerId; + } + + public function sendEvent(string $topic, $message): void + { + $this->getRealProducer()->sendEvent($topic, $message); + } + + public function sendCommand(string $command, $message, bool $needReply = false): ?Promise + { + return $this->getRealProducer()->sendCommand($command, $message, $needReply); + } + + private function getRealProducer(): ProducerInterface + { + return $this->container->get($this->producerId); + } +} diff --git a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php index c0142f0e3..4d95ca07d 100644 --- a/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php +++ b/pkg/enqueue/Tests/Symfony/Client/DependencyInjection/BuildProcessorRegistryPassTest.php @@ -136,10 +136,10 @@ private function assertLocatorServices(ContainerBuilder $container, $locatorId, $locatorId = (string) $locatorId; $this->assertTrue($container->hasDefinition($locatorId)); - $this->assertRegExp('/service_locator\..*?\.enqueue\./', $locatorId); + $this->assertRegExp('/\.?service_locator\..*?\.enqueue\./', $locatorId); $match = []; - if (false == preg_match('/(service_locator\..*?)\.enqueue\./', $locatorId, $match)) { + if (false == preg_match('/(\.?service_locator\..*?)\.enqueue\./', $locatorId, $match)) { $this->fail('preg_match should not failed'); } diff --git a/pkg/enqueue/Tests/Symfony/DependencyInjection/BuildProcessorRegistryPassTest.php b/pkg/enqueue/Tests/Symfony/DependencyInjection/BuildProcessorRegistryPassTest.php index d122e044c..989d048cf 100644 --- a/pkg/enqueue/Tests/Symfony/DependencyInjection/BuildProcessorRegistryPassTest.php +++ b/pkg/enqueue/Tests/Symfony/DependencyInjection/BuildProcessorRegistryPassTest.php @@ -199,10 +199,10 @@ private function assertLocatorServices(ContainerBuilder $container, $locatorId, $locatorId = (string) $locatorId; $this->assertTrue($container->hasDefinition($locatorId)); - $this->assertRegExp('/service_locator\..*?\.enqueue\./', $locatorId); + $this->assertRegExp('/\.?service_locator\..*?\.enqueue\./', $locatorId); $match = []; - if (false == preg_match('/(service_locator\..*?)\.enqueue\./', $locatorId, $match)) { + if (false == preg_match('/(\.?service_locator\..*?)\.enqueue\./', $locatorId, $match)) { $this->fail('preg_match should not failed'); } diff --git a/pkg/enqueue/Tests/Symfony/LazyProducerTest.php b/pkg/enqueue/Tests/Symfony/LazyProducerTest.php new file mode 100644 index 000000000..b574414c7 --- /dev/null +++ b/pkg/enqueue/Tests/Symfony/LazyProducerTest.php @@ -0,0 +1,133 @@ +assertClassImplements(ProducerInterface::class, LazyProducer::class); + } + + public function testCouldBeConstructedWithContainerAndServiceId() + { + new LazyProducer($this->createContainerMock(), 'realProducerId'); + } + + public function testShouldNotCallRealProducerInConstructor() + { + $containerMock = $this->createContainerMock(); + $containerMock + ->expects($this->never()) + ->method('get') + ; + + new LazyProducer($containerMock, 'realProducerId'); + } + + public function testShouldProxyAllArgumentOnSendEvent() + { + $topic = 'theTopic'; + $message = 'theMessage'; + + $realProducerMock = $this->createProducerMock(); + $realProducerMock + ->expects($this->once()) + ->method('sendEvent') + ->with($topic, $message) + ; + + $containerMock = $this->createContainerMock(); + $containerMock + ->expects($this->once()) + ->method('get') + ->with('realProducerId') + ->willReturn($realProducerMock) + ; + + $lazyProducer = new LazyProducer($containerMock, 'realProducerId'); + + $lazyProducer->sendEvent($topic, $message); + } + + public function testShouldProxyAllArgumentOnSendCommand() + { + $command = 'theCommand'; + $message = 'theMessage'; + $needReply = false; + + $realProducerMock = $this->createProducerMock(); + $realProducerMock + ->expects($this->once()) + ->method('sendCommand') + ->with($command, $message, $needReply) + ; + + $containerMock = $this->createContainerMock(); + $containerMock + ->expects($this->once()) + ->method('get') + ->with('realProducerId') + ->willReturn($realProducerMock) + ; + + $lazyProducer = new LazyProducer($containerMock, 'realProducerId'); + + $result = $lazyProducer->sendCommand($command, $message, $needReply); + + $this->assertNull($result); + } + + public function testShouldProxyReturnedPromiseBackOnSendCommand() + { + $expectedPromise = $this->createMock(Promise::class); + + $realProducerMock = $this->createProducerMock(); + $realProducerMock + ->expects($this->once()) + ->method('sendCommand') + ->willReturn($expectedPromise) + ; + + $containerMock = $this->createContainerMock(); + $containerMock + ->expects($this->once()) + ->method('get') + ->with('realProducerId') + ->willReturn($realProducerMock) + ; + + $lazyProducer = new LazyProducer($containerMock, 'realProducerId'); + + $actualPromise = $lazyProducer->sendCommand('aCommand', 'aMessage', true); + + $this->assertSame($expectedPromise, $actualPromise); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|ProducerInterface + */ + private function createProducerMock(): ProducerInterface + { + return $this->createMock(ProducerInterface::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|ContainerInterface + */ + private function createContainerMock(): ContainerInterface + { + return $this->createMock(ContainerInterface::class); + } +} diff --git a/pkg/job-queue/Tests/Functional/WebTestCase.php b/pkg/job-queue/Tests/Functional/WebTestCase.php index 329762004..ecb6e5af9 100644 --- a/pkg/job-queue/Tests/Functional/WebTestCase.php +++ b/pkg/job-queue/Tests/Functional/WebTestCase.php @@ -11,7 +11,7 @@ abstract class WebTestCase extends BaseWebTestCase /** * @var Client */ - protected $client; + protected static $client; /** * @var ContainerInterface @@ -24,7 +24,7 @@ protected function setUp() static::$class = null; - $this->client = static::createClient(); + static::$client = static::createClient(); if (false == static::$container) { static::$container = static::$kernel->getContainer();