给出了这个传奇:
@Saga
@Getter
@Slf4j
public class TasksForStateSaga {
@Autowired
transient CommandGateway commandGateway;
@Autowired
transient EventBus eventBus;
@Autowired
transient TaskService taskService;
Map<String, TaskStatus> tasks = new HashMap<>();
ApplicationState applicationState;
@StartSaga
@SagaEventHandler(associationProperty = "id")
public void on(ApplicationStateChangedEvent event) {
applicationState = event.getNewState();
log.info("Planning tasks for application {} in state {}", event.getId(), applicationState);
taskService.getTasksByState(applicationState).stream()
.map(task -> ScheduleTaskCommand.builder()
.applicationId(event.getId())
.taskId(IdentifierFactory.getInstance().generateIdentifier())
.targetState(applicationState)
.taskName(task.getTaskName())
.build())
.peek(command -> tasks.put(command.getTaskId(), SCHEDULED))
.forEach(command -> commandGateway.send(command));
}
@SagaEventHandler(associationProperty = "applicationId")
public void on(TaskFinishedEvent event) {
tasks.replace(event.getTaskId(), FINISHED);
long notFinished = getUnfinishedCount();
log.info("Task {} has just finished, ready {} of {}", event.getTaskName(), tasks.size() - notFinished, tasks.size());
if (notFinished == 0) {
log.info("All tasks for application {}.{} finished, ending this saga", event.getApplicationId(), applicationState);
eventBus.publish(GenericEventMessage.asEventMessage(
TaskForStateDoneEvent.builder()
.applicationId(event.getApplicationId())
.state(applicationState)
.build()
));
SagaLifecycle.end();
}
}
private long getUnfinishedCount() {
return tasks.values().stream()
.filter(state -> !FINISHED.equals(state))
.count();
}
}
让此测试(Spock)测试第一种方法:
class TasksForStateSagaTest extends Specification {
SagaTestFixture sagaFixture
def setup() {
sagaFixture = new SagaTestFixture<>(TasksForStateSaga)
}
def 'should schedule task for the application state'() {
given:
def applicationId = '1'
def taskService = Mock(TaskService)
def tasks = [
ApplicationStateAwareTaskDefinition.builder().taskName('task1').build(),
ApplicationStateAwareTaskDefinition.builder().taskName('task2').build(),
]
sagaFixture.registerResource(taskService)
sagaFixture.givenAggregate(applicationId)
when:
sagaFixture
.whenPublishingA(new ApplicationStateChangedEvent(id: applicationId, newState: ApplicationState.NEW))
.expectActiveSagas(1)
.expectDispatchedCommandsMatching(payloadsMatching(
exactSequenceOf(
equalTo(new ScheduleTaskCommand(applicationId: applicationId, targetState: ApplicationState.NEW, taskName: 'task1'),
new IgnoreField(ScheduleTaskCommand, 'taskId')),
equalTo(new ScheduleTaskCommand(applicationId: applicationId, targetState: ApplicationState.NEW, taskName: 'task2'),
new IgnoreField(ScheduleTaskCommand, 'taskId')),
andNoMore()
)
))
then:
1 * taskService.getTasksByState(ApplicationState.NEW) >> tasks
}
}
但是我实际上不知道如何测试使用Saga内部状态的第二种方法。
有人可以建议我如何通过SagaTestFixture设置内部传奇状态吗? 甚至更多,这是实现此类传奇的好方法,还是我遇到了一些概念上的问题,使我无法轻松测试终结传奇方法?
@StartSaga方法设置内部状态-生成taskId并将其设置为map @EndSaga方法读取地图并在发送TaskForStateDoneEvent事件之前检查所有任务是否已完成
谢谢!
答案 0 :(得分:1)
我通过为saga装置定义回调实现了这一点。该回调捕获所需类型的所有命令,并临时存储ids
def 'saga should end when all scheduled tasks finished'() {
given:
def applicationId = '1'
def taskService = Mock(TaskService)
def tasks = [
ApplicationStateAwareTaskDefinition.builder().taskName('task1').build(),
ApplicationStateAwareTaskDefinition.builder().taskName('task2').build(),
]
def scheduleTaskCommands = []
sagaFixture.registerResource(taskService)
sagaFixture.setCallbackBehavior(new CallbackBehavior() {
@Override
Object handle(Object commandPayload, MetaData commandMetaData) {
if (commandPayload instanceof ScheduleTaskCommand) {
// catch the issued commands to get the new task ids
scheduleTaskCommands << commandPayload
}
commandPayload
}
})
when:
sagaFixture
.givenAggregate(applicationId)
.published(new ApplicationStateChangedEvent(
applicationId: applicationId,
newState: ApplicationState.NEW
))
// publish event to finish first task (first from two)
sagaFixture.givenAPublished(new TaskFinishedEvent(
taskName: 'someTaskName',
applicationId: applicationId,
taskId: scheduleTaskCommands[0].taskId,
taskResult: new TaskResult(
status: TaskResultStatus.SUCCEED,
message: 'ok'
)))
// verify the behaviour after second task finished
sagaFixture
.whenPublishingA(new TaskFinishedEvent(
taskName: 'someTaskName',
applicationId: applicationId,
taskId: scheduleTaskCommands[1].taskId,
taskResult: new TaskResult(
status: TaskResultStatus.SUCCEED,
message: 'ok'
)))
.expectActiveSagas(0)
.expectPublishedEvents(new TasksForStateFinishedEvent(
applicationId: applicationId,
state: ApplicationState.NEW
))
then:
1 * taskService.getTasksByState(ApplicationState.NEW) >> tasks
}