Class SynchronousNotificationExecutorTestConfiguration

java.lang.Object
com.broadleafcommerce.common.jpa.autoconfigure.SynchronousNotificationExecutorTestConfiguration

@Configuration @ConditionalOnClass(name="com.broadleafcommerce.common.messaging.notification.NotificationManager") @ConditionalOnProperty(name="spring.test.database.synchronous-notifications", matchIfMissing=true) public class SynchronousNotificationExecutorTestConfiguration extends Object
Runs notification handling inline on the thread that committed the change, rather than on the notification thread pool, for any test declaring AutoConfigureTestDb.

NotificationManager#handleAsync(..) hands the message send to notificationMessageAsyncExecutor, so work caused by one test can run after that test has already returned. Three things follow from that, and all three have produced intermittent test failures:

  • A message emitted by one test can be consumed by the next. Where a service binds an input and an output to the same destination - persistence, typically - the emission also loops back into the service under test, so the consumer runs at an unpredictable point.
  • DefaultNotificationHandler acknowledges the send by way of a REQUIRES_NEW update against the notification state table. That write races whatever the test does next, including an @AfterEach that clears the schema.
  • Draining a message collector between tests evicts what has already landed, but it is a barrier rather than a fence - it cannot stop a message that arrives afterwards.
Substituting a SyncTaskExecutor closes that window: every emission, and every write that follows from it, completes within the test method that caused it.

This replaces the executor rather than disabling async handling through broadleaf.notification.manager.async-enabled, so tests still exercise the production branch of handleAsync(..). The threading guarantees of that branch are covered directly by MicroMessagingCommon's DefaultNotificationManagerTest.

A test that is deliberately asserting on pooled behavior opts out with @AutoConfigureTestDb(synchronousNotifications = false).

Author:
Jeff Fischer
See Also:
  • Field Details

  • Constructor Details

    • SynchronousNotificationExecutorTestConfiguration

      public SynchronousNotificationExecutorTestConfiguration()
  • Method Details

    • synchronousNotificationExecutorPostProcessor

      @Bean public static org.springframework.beans.factory.config.BeanFactoryPostProcessor synchronousNotificationExecutorPostProcessor()
      Replaces the pooled executor after every bean definition is known, rather than competing to declare the bean first.

      Declaring a rival @Bean would work only when the pool arrives by way of auto-configuration, where @AutoConfigureBefore can order the two and the pool's @ConditionalOnMissingBean(name = ..) can then back off. Several tests instead @Import DurableNotificationAutoConfiguration directly, which is parsed as an ordinary configuration class - no auto-configuration ordering, no condition evaluated against anything, and two definitions bound to one name. A post-processor sidesteps the ordering question entirely, because by the time it runs there is nothing left to race.

      Only the stock pool is replaced. A test that supplies its own executor under this name meant to, and keeps it.