zenstruck / messenger-test

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

Error sending message to new transport from an EntityListener #81

Open mbopp opened 5 months ago

mbopp commented 5 months ago

I'm using API Platform. I have many transports and many tests that work great. But after adding a new transport and implementing a test I am getting an error:

 TypeError: Zenstruck\Messenger\Test\Transport\TestTransport::isIntercepting(): Return value must be of type bool, null returned

Which seems to indicate that the new transport isn't found. Here are some of the details that cause this error ('hubspot_transport' is the name of the one that fails)

messenger.yaml

framework:
    messenger:
        reset_on_message: true
        default_bus: event.bus
        buses:
            event.bus:
                default_middleware: allow_no_handlers
                middleware:
                    - App\Messenger\AuditMiddleware

        failure_transport: failed

        transports:
            async_transport:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            hubspot_transport:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                retry_strategy:
                    max_retries: 1
            failed: 'doctrine://default?queue_name=failed'

        routing:
            'App\Message\ActivityMessage': async_transport
            'App\Message\HubspotUpdateMessage': hubspot_transport

when@test:
    framework:
        messenger:
            transports:
              async_transport: 'test://'
              hubspot_transport: 'test://'

when@dev:
    framework:
        messenger:
            transports:
              async_transport: '%env(MESSENGER_TRANSPORT_DSN)%'
              hubspot_transport: '%env(MESSENGER_TRANSPORT_DSN)%'

relevant test code:

    $client = self::createClient();

    $messenger = $this->transport('hubspot_transport');

    // Error ONLY occurs when this statement exists.
    $messenger->resetAll(); 

    // This request produces error 
    $client->request('POST', '/api/authentication/token', [
      'headers' => ['Content-Type' => 'application/json'],
      'json' => [
        'username' => $username,
        'password' => $password,
      ],
    ]);

The login request alters a field on the user entity...

In my entity listener:

#[AsEntityListener(event: Events::preUpdate, method: 'preUpdate', entity: User::class)]
class UserListener
{
  public function __construct(
    private readonly MessageBusInterface $messageBus,
  ) {
  }

  public function preUpdate(User $user, PreUpdateEventArgs $event): void
  {
    $hubspotMessage = new HubspotUpdateMessage(HubspotUpdateType::CONTACT, $user->getId(), ['updating user']);
    $this->messageBus->dispatch($hubspotMessage); // <<< Error
  }
...
}

Please let me know if there is more info I can provide to help put a finger on what is happening here. Thank you so much for your help!

nikophil commented 5 months ago

Hello @mbopp

I think that if you use $messenger->reset() you won't have the problem.

nonetheless, there is a problem with resetAll() method: we're resetting $intercept and $catchExceptions to null, but isIntercepting() and isCatchingExceptions() must return false. @kbond WDYT?

kbond commented 5 months ago

I think that if you use $messenger->reset() you won't have the problem.

@mbopp, can you confirm this solves the problem?

I don't think resetAll should be used in userland - we should mark as internal. It should only be called in the test trait.

nonetheless, there is a problem with resetAll() method: we're resetting $intercept and $catchExceptions to null, but isIntercepting() and isCatchingExceptions() must return false.

I think the problem is an undefined array key (there's a warning but returns null). We should throw an exception here I think.

mbopp commented 5 months ago

Thanks for the quick response!

That fixed it! I'm very appreciative! This is a fantastic utility.