zenstruck / messenger-test

Assertions and helpers for testing your symfony/messenger queues.
MIT License
223 stars 15 forks source link

Problem with intercept() #7

Closed abeal-hottomali closed 3 years ago

abeal-hottomali commented 3 years ago

Noticed this recently when running a longer test: About halfway through, the transport had to be reconstructed as a service. When that happened, the values from the config were used (config/packages/test/messenger.yaml), and the call to intercept() earlier in the test was no longer honoured.

My configuration value for the transport in question:

# config/packages/test/messenger.yaml
framework:
    messenger:
        transports:
            # Uses zenstruck messenger transport for testing sent messages
            sync:
                dsn: test://?intercept=false&catch_exceptions=false

I'm trying to change this transport to intercept = true for the length of a given test. It works initially, but the value resets when the service is regenerated. See also the options passed in \Zenstruck\Messenger\Test\Transport\TestTransportFactory::createTransport, and the options expected in \Zenstruck\Messenger\Test\Transport\TestTransport::__construct

abeal-hottomali commented 3 years ago

One possible resolution to this.

// \Zenstruck\Messenger\Test\Transport\TestTransportFactory

    private static $lastTransports = [];

    public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface
    {
        $transport_options = $this->parseDsn($dsn);
        if (array_key_exists($options['transport_name'], self::$lastTransports)) {
            /* @var \Zenstruck\Messenger\Test\Transport\TestTransport $last_transport */
            $last_transport = self::$lastTransports[$options['transport_name']];
            // Port any options set on the last transport.
            $last_transport_options = [
                'intercept' => $last_transport->getIntercept(),
                'catch_exceptions' => $last_transport->getCatchExceptions()
            ];
            $transport_options = array_merge($transport_options, $last_transport_options);
        }
        $result = new TestTransport($options['transport_name'], $this->bus, $serializer, $transport_options);
        self::$lastTransports[$options['transport_name']] = $result;
        return $result;
    }
// \Zenstruck\Messenger\Test\Transport\TestTransport

    /**
     * @return bool|mixed
     */
    public function getIntercept(): bool
    {
        return $this->intercept;
    }

    /**
     * @return bool|mixed
     */
    public function getCatchExceptions(): bool
    {
        return $this->catchExceptions;
    }
kbond commented 3 years ago

Thanks for the report @abeal-hottomali. #8 adds failing tests to demonstrate the problem. I'll work on a fix.

kbond commented 3 years ago

FYI - should be fixed in v0.3.0 but let me know if not.

abeal-hottomali commented 3 years ago

I tried this version, and I'm now running into a separate issue. With my default configuration

            sync:
                dsn: test://?intercept=false&catch_exceptions=false

I'm seeing the error:

"The \"kernel\" service is synthetic, it needs to be set at boot time before it can be used.",

When I change the configuration to be intercept:true, the tests operate as expected (currently, the tests in question don't need what the messenger task accomplishes to complete successfully). I'm not sure what is going on. It seems like the change here might have had an impact, but I'm still digging to try to find out.

kbond commented 3 years ago

Ok, thanks, I'll look into this.

When does this error occur? When you call $this->messenger()? If so, can you see if the kernel is booted before making this call (self::$booted should === true).

abeal-hottomali commented 3 years ago

I've been pulled away into something else, but yes, I'll look and get back to you as soon as I'm able. I can tell you off the top of my head that the tests involved don't even use InteractsWithMessenger.

For reference, this is my project's default messenger.yaml:

framework:
    messenger:
        # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
        failure_transport: failed

        transports:
            # By default, messages are handled as soon as they are dispatched. If you want to 
            # handle a message asynchronously, you can configure a transport. 
            # A transport is capable of sending messages (e.g. to a queueing system) and then 
            # receiving them via a worker. Messenger supports multiple transports.
            # See https://symfony.com/doc/current/messenger.html#transports-async-queued-messages

            # Processed by the AMQP messenger transport asynchronously. Handlers
            # sent here cannot be relied on for their return values immediately.
            # This is by design.
            # AMQP transport options can be found at 
            # https://symfony.com/doc/current/messenger.html#amqp-transport
            async:
                dsn: '%env(trim:resolve:MESSENGER_TRANSPORT_DSN)%'
                options:
                    auto_setup: true
            # Sync is explicitly spelled out even though it just specifies default values
            # to allow changing message transports based on environment if necessary.
            # https://symfony.com/doc/current/messenger.html#handling-messages-synchronously
            sync: 
                dsn: 'sync://'

            # Let doctrine handle the failed message queue for now. 
            # (This may be better done by amqp - revisit).
            failed:
                dsn: 'doctrine://default?queue_name=failed'
                options:
                    auto_setup: true

And this is for the testing environment:

framework:
    messenger:
        transports:
            # Process async transport using zenstruck test transport.  This allows us
            # to ensure messages were fired upon certain events, and optionally still
            # process them.
            # Uses zenstruck messenger transport for testing sent messages:
            # https://github.com/zenstruck/messenger-test#queue-assertions
            async:
                dsn: test://
            # Use the test transport for sync messages as well, so we have the option to
            # block in a given integration test, and confirm a message was sent, or just
            # let the message be processed normally.
            sync:
                dsn: test://?intercept=false&catch_exceptions=false
kbond commented 3 years ago

So do your tests using the async transport work fine?

kbond commented 3 years ago

@OskarStark has discovered, I think, the same problem as you, I'm tracking in #9.

kbond commented 3 years ago

This should be fixed in v0.3.1 but let me know if it isn't.

abeal-hottomali commented 3 years ago

Thank you, I'll be back on this tomorrow and will give it a go!

-- Aron Beal Developer Team Lead @.***

Hot Tomali Communications 1441 East Pender Street Vancouver BC  V5L 1V7 P 604.893.8347 P 604.893.8346

www.hottomali.com

On May 14, 2021, 3:30 PM -0700, Kevin Bond @.***>, wrote:

This should be fixed in v0.3.1 but let me know if it isn't. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

abeal-hottomali commented 3 years ago

Confirmed that this is working for me ok in v0.3.1, thanks!

kbond commented 3 years ago

Thanks for the update!