All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.axonframework.test.saga.FixtureConfiguration Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2023. Axon Framework
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.axonframework.test.saga;

import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.CommandResultMessage;
import org.axonframework.deadline.DeadlineMessage;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.EventMessage;
import org.axonframework.eventhandling.ListenerInvocationErrorHandler;
import org.axonframework.messaging.MessageDispatchInterceptor;
import org.axonframework.messaging.MessageHandlerInterceptor;
import org.axonframework.messaging.annotation.HandlerDefinition;
import org.axonframework.messaging.annotation.HandlerEnhancerDefinition;
import org.axonframework.messaging.annotation.ParameterResolver;
import org.axonframework.messaging.annotation.ParameterResolverFactory;
import org.axonframework.modelling.saga.ResourceInjector;
import org.axonframework.test.FixtureExecutionException;
import org.axonframework.test.aggregate.ResultValidator;
import org.axonframework.test.matchers.FieldFilter;
import org.axonframework.test.utils.CallbackBehavior;

import java.time.Instant;


/**
 * Interface describing action to perform on a Saga Test Fixture during the configuration phase.
 *
 * @author Allard Buijze
 * @since 1.1
 */
public interface FixtureConfiguration {

    /**
     * Disables the check that injected resources are stored in fields that are marked 'transient'.
     * 

* By default, Saga fixtures check for the transient modifier on fields that hold injected resources. These * resources are generally not means to be serialized as part of the Saga. *

* When the transience check reports false positives, this method allows this check to be skipped. * * @return this instance for fluent interfacing. */ FixtureConfiguration withTransienceCheckDisabled(); /** * Registers the given {@code resource}. When a Saga is created, all resources are injected on that instance before * any Events are passed onto it. *

* Note that a CommandBus, EventBus and EventScheduler are already registered as resources, and need not be * registered again. *

* Also note that you might need to reset the resources manually if you want to isolate behavior during the "when" * stage of the test. * * @param resource the resource to register. */ void registerResource(Object resource); /** * Registers a {@link ParameterResolverFactory} within this fixture. The given {@code parameterResolverFactory} will * be added to the other parameter resolver factories introduced through {@link * org.axonframework.messaging.annotation.ClasspathParameterResolverFactory#forClass(Class)} and the {@link * org.axonframework.messaging.annotation.SimpleResourceParameterResolverFactory} adding the registered resources * (with {@link #registerResource(Object)}. The type of the saga under test is used as input for the {@code * ClasspathParameterResolverFactory#forClass(Class)} operation. * * @param parameterResolverFactory the {@link ParameterResolver} to register within this fixture * @return the current FixtureConfiguration, for fluent interfacing * @see #registerResource(Object) */ FixtureConfiguration registerParameterResolverFactory(ParameterResolverFactory parameterResolverFactory); /** * Creates a Command Gateway for the given {@code gatewayInterface} and registers that as a resource. The gateway * will dispatch commands on the Command Bus contained in this Fixture, so that you can validate commands using * {@link FixtureExecutionResult#expectDispatchedCommands(Object...)} and {@link * FixtureExecutionResult#expectDispatchedCommandsMatching(org.hamcrest.Matcher)}. *

* Note that you need to use {@link #setCallbackBehavior(org.axonframework.test.utils.CallbackBehavior)} to defined * the behavior of commands when expecting return values. Alternatively, you can use {@link * #registerCommandGateway(Class, Object)} to define behavior using a stub implementation. * * @param gatewayInterface The interface describing the gateway * @param The gateway type * @return the gateway implementation being registered as a resource. */ T registerCommandGateway(Class gatewayInterface); /** * Creates a Command Gateway for the given {@code gatewayInterface} and registers that as a resource. The gateway * will dispatch commands on the Command Bus contained in this Fixture, so that you can validate commands using * {@link FixtureExecutionResult#expectDispatchedCommands(Object...)} and {@link * FixtureExecutionResult#expectDispatchedCommandsMatching(org.hamcrest.Matcher)}. *

* The behavior of the created gateway is defined by the given {@code stubImplementation}, if not null. Dispatched * Commands are still recorded for verification. Note that only commands executed in the "when" phase are recorded, * while the stub implementation may record activity during the "given" phase as well. * * @param gatewayInterface The interface describing the gateway * @param stubImplementation The stub or mock implementation defining behavior of the gateway * @param The gateway type * @return the gateway implementation being registered as a resource. */ T registerCommandGateway(Class gatewayInterface, T stubImplementation); /** * Registers the given {@code fieldFilter}, which is used to define which Fields are used when comparing objects. * The {@link ResultValidator#expectEvents(Object...)} and {@link ResultValidator#expectResultMessage(CommandResultMessage)}, * for example, use this filter. *

* When multiple filters are registered, a Field must be accepted by all registered filters in order to be * accepted. *

* By default, all Fields are included in the comparison. * * @param fieldFilter The FieldFilter that defines which fields to include in the comparison * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerFieldFilter(FieldFilter fieldFilter); /** * Indicates that a field with given {@code fieldName}, which is declared in given {@code declaringClass} is ignored * when performing deep equality checks. * * @param declaringClass The class declaring the field * @param fieldName The name of the field * @return the current FixtureConfiguration, for fluent interfacing * @throws FixtureExecutionException when no such field is declared */ FixtureConfiguration registerIgnoredField(Class declaringClass, String fieldName); /** * Registers a {@link HandlerDefinition} within this fixture. The given {@code handlerDefinition} is added to the * handler definitions introduced through {@link org.axonframework.messaging.annotation.ClasspathHandlerDefinition#forClass(Class)}. * The type of the saga under test is used as input for the {@code ClasspathHandlerDefinition#forClass(Class)} * operation. * * @param handlerDefinition used to create concrete handlers * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerHandlerDefinition(HandlerDefinition handlerDefinition); /** * Registers a {@link HandlerEnhancerDefinition} within this fixture. This given {@code handlerEnhancerDefinition} * is added to the handler enhancer definitions introduced through {@link org.axonframework.messaging.annotation.ClasspathHandlerEnhancerDefinition#forClass(Class)}. * The type of the saga under test is used as input for the {@code ClasspathHandlerEnhancerDefinition#forClass(Class)} * operation. * * @param handlerEnhancerDefinition the {@link HandlerEnhancerDefinition} to register within this fixture * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerHandlerEnhancerDefinition(HandlerEnhancerDefinition handlerEnhancerDefinition); /** * Registers a deadline dispatch interceptor which will always be invoked before a deadline is dispatched * (scheduled) on the {@link org.axonframework.deadline.DeadlineManager} to perform a task specified in the * interceptor. * * @param deadlineDispatchInterceptor the interceptor for dispatching (scheduling) deadlines * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerDeadlineDispatchInterceptor( MessageDispatchInterceptor> deadlineDispatchInterceptor ); /** * Registers a deadline handler interceptor which will always be invoked before a deadline is handled to perform a * task specified in the interceptor. * * @param deadlineHandlerInterceptor the interceptor for handling deadlines * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerDeadlineHandlerInterceptor( MessageHandlerInterceptor> deadlineHandlerInterceptor ); /** * Registers a {@link MessageHandlerInterceptor} for {@link EventMessage EventMessages}. *

* Will always be invoked before an event is handled to perform a task specified in the interceptor. Interceptors * are invoked in the order they have been registered in. * * @param eventHandlerInterceptor the interceptor for handling {@link EventMessage EventMessages} * @return The current {@link FixtureConfiguration}, for fluent interfacing. */ default FixtureConfiguration registerEventHandlerInterceptor( MessageHandlerInterceptor> eventHandlerInterceptor ) { throw new UnsupportedOperationException( "The FixtureConfiguration implementation does not support this operation" ); } /** * Registers a callback to be invoked when the fixture execution starts recording. This happens right before * invocation of the 'when' step (stimulus) of the fixture. *

* Use this to manage Saga dependencies which are not an Axon first class citizen, but do require monitoring of * their interactions. For example, register the callback to set a mock in recording mode. * * @param onStartRecordingCallback callback to invoke * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerStartRecordingCallback(Runnable onStartRecordingCallback); /** * Registers a {@link ListenerInvocationErrorHandler} to be set for the Saga to deal with exceptions being thrown from within Saga Event Handlers. Will be * given to the {@link org.axonframework.modelling.saga.AnnotatedSagaManager} for the defined Saga type. Defaults to a {@link * org.axonframework.eventhandling.LoggingErrorHandler} wrapped inside a {@link RecordingListenerInvocationErrorHandler}. * * @param listenerInvocationErrorHandler to be set for the Saga to deal with exceptions being thrown from within Saga Event Handlers * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerListenerInvocationErrorHandler( ListenerInvocationErrorHandler listenerInvocationErrorHandler); /** * Configure whether the fixture should suppress exceptions thrown during the given-phase. When {@code suppress} is * {@code true}, the fixture moves on to the when-phase regardless of any exceptions thrown during the given-phase. *

* Note that setting this to {@code true} means the * {@link #registerListenerInvocationErrorHandler(ListenerInvocationErrorHandler) registered} * {@link ListenerInvocationErrorHandler} is not invoked during exception in the given-phase. Defaults to * suppressing during given-phase exceptions. * * @param suppress A {@code boolean} describing whether the fixture should suppress failures during the * given-phase. * @return The current fixture, for fluent interfacing. */ default FixtureConfiguration suppressExceptionInGivenPhase(boolean suppress) { return this; } /** * Registers a {@link ResourceInjector} within this fixture. This approach can be used if a custom {@code * ResourceInjector} has been built for a project which the user wants to take into account when testing it's * sagas. *

* The provided {@code resourceInjector} will be paired with the fixture's default {@code ResourceInjector} to keep * support for the {@link #registerResource(Object)} and {@link #withTransienceCheckDisabled()} methods. Note that * first the default injector is called, and after that the given {@code resourceInjector}. This approach * ensures the fixture's correct workings for default provided resources, like the {@link EventBus} and {@link * CommandBus}}, whilst allowing the capability to append and/or override with the given {@code resourceInjector}. *

* Care should be taken if the custom {@code resourceInjector} overrides default resources like the {@code EventBus} * and {@code CommandBus}, as the fixture uses specialized versions of the default sources to support all testing * functionality. * * @param resourceInjector the {@link ResourceInjector} to register within this fixture * @return the current FixtureConfiguration, for fluent interfacing */ FixtureConfiguration registerResourceInjector(ResourceInjector resourceInjector); /** * Sets the instance that defines the behavior of the Command Bus when a command is dispatched with a callback. * * @param callbackBehavior The instance deciding to how the callback should be invoked. */ void setCallbackBehavior(CallbackBehavior callbackBehavior); /** * Use this method to indicate that an aggregate with given identifier published certain events. *

* Can be chained to build natural sentences:
{@code andThenAggregate(someIdentifier).published(someEvents)} * * @param aggregateIdentifier The identifier of the aggregate the events should appear to come from * @return an object that allows registration of the actual events to send */ GivenAggregateEventPublisher givenAggregate(String aggregateIdentifier); /** * Use this method to indicate a specific moment as the initial current time "known" by the fixture at the start of * the given state. * * @param currentTime The simulated "current time" at which the given state is initialized * @return an object that allows chaining of more given state */ ContinuedGivenState givenCurrentTime(Instant currentTime); /** * Indicates that the given {@code applicationEvent} has been published in the past. This event is sent to the * associated sagas. * * @param event The event to publish * @return an object that allows chaining of more given state */ ContinuedGivenState givenAPublished(Object event); /** * Indicates that no relevant activity has occurred in the past. * * @return an object that allows the definition of the activity to measure Saga behavior * @since 2.1.1 */ WhenState givenNoPriorActivity(); /** * Returns the time as "known" by the fixture. This is the time at which the fixture was created, plus the amount of * time the fixture was told to simulate a "wait". *

* This time can be used to predict calculations that the saga may have made based on timestamps from the events it * received. * * @return the simulated "current time" of the fixture. */ Instant currentTime(); /** * Returns the event bus used by this fixture. The event bus is provided for wiring purposes only, for example to * allow command handlers to publish events other than Domain Events. Events published on the returned event bus are * recorded an evaluated in the {@link ResultValidator} operations. * * @return the event bus used by this fixture */ EventBus getEventBus(); /** * Returns the command bus used by this fixture. The command bus is provided for wiring purposes only, for example * to support composite commands (a single command that causes the execution of one or more others). * * @return the command bus used by this fixture */ CommandBus getCommandBus(); }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy