I have encountered an issue when testing saga with SagaTestFixture.
When using time shifts via whenTimeElapses() or andThenTimeElapses(), to test scheduled events, I noticed that the @Timestamp timestamps are not set to the future time.
To depict the issue above, please find below example saga with failing test.
Thanks a lot for help.
Best regards,
Przemek
Saga:
@Saga
public class TestSaga {
@Setter(onMethod = @__(@Autowired))
private transient EventScheduler eventScheduler;
@Autowired
private transient CommandGateway commandGateway;
@StartSaga
@SagaEventHandler(associationProperty = "id")
public void startSaga(final Event event, @Timestamp Instant eventTimestamp) {
Instant triggerTime = eventTimestamp.plus(Duration.ofMinutes(30));
this.eventScheduler.schedule(triggerTime, new ScheduledEvent(event.getId()));
}
@SagaEventHandler(associationProperty = "id")
public void handle(final ScheduledEvent event, @Timestamp Instant eventTimestamp) {
commandGateway.send(new TestCommand(event.getId(), eventTimestamp));
}
}
@Value
class TestCommand {
String id;
Instant timestamp;
}
@Value
class Event {
String id;
}
@Value
class ScheduledEvent {
String id;
}
Test:
@RunWith(SpringRunner.class)
public class TestSagaTest {
private SagaTestFixture<TestSaga> fixture;
@Before
public void setup() {
fixture = new SagaTestFixture<>(TestSaga.class);
}
@Test
public void should() {
String id = "id";
Instant time = fixture.currentTime().plus(Duration.ofMinutes(60));
fixture.givenAggregate(id)
.published(new Event(id))
.whenTimeElapses(Duration.ofMinutes(60))
.expectDispatchedCommands(new TestCommand(id, time));
}
}
you haven’t set the initial time of the test. In that case, it will assume the timestamp at which the fixture is created. While it’s close, it’s not exactly the same moment as your “time” variable.
If you want to set the current time to your “time” variable, use:
fixture.givenCurrentTime(time).andThenAggregate(id).published(new Event(id)…
Thanks for point that thing out that time mismatch. Im sorry for not being clear enough. What Im trying to point out / ask about, is that the @Timestamp received on handling event published by EventScheduler is not either properly shifted in future nor it is taking into the consideration the fixture.givenCurrentTime. I have added explicit point in time so we can refer to the same times.
Given the snippet below, flow I would anticipate to see would be:
Event is handled with @Timestamp2018-01-01T00:00:00Z
It is scheduling sending Scheduled**Event for 2018-01-01T00:30:00Z 3) When we rewind the time with whenTimeElapses() with 60 minutes, the scheduler is publishing the Scheduled**Event, but it is handled with @Timestamp 2018-10-26T13:19:07.233664Z (My local current date :D),
and I would suspect it would be set to the 2018-01-01T00:30:00Z.
Thanks again for such quick response.
Best regards,
Przemek
Test:
@Test
public void should() throws ParseException {
String id = "id";
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Instant referenceTime = dateFormat.parse("2018-01-01T10:00:00").toInstant();
Instant time = referenceTime.plus(Duration.ofMinutes(30));
fixture.givenCurrentTime(referenceTime)
.andThenAggregate(id)
.published(new Event(id))
.whenTimeElapses(Duration.ofMinutes(60))
.expectDispatchedCommands(new TestCommand(id, time));
}
Saga:
@Saga
public class TestSaga {
@Setter(onMethod = @__(@Autowired))
private transient EventScheduler eventScheduler;
@Autowired
private transient CommandGateway commandGateway;
@StartSaga
@SagaEventHandler(associationProperty = "id")
public void startSaga(final Event event, @Timestamp Instant eventTimestamp) {
Instant triggerTime = eventTimestamp.plus(Duration.ofMinutes(30));
this.eventScheduler.schedule(triggerTime, new ScheduledEvent(event.getId()));
}
@SagaEventHandler(associationProperty = "id")
public void handle(final ScheduledEvent event, @Timestamp Instant eventTimestamp) {
commandGateway.send(new TestCommand(event.getId(), eventTimestamp));
}
}
@Value
class TestCommand {
String id;
Instant timestamp;
}
@Value
class Event {
String id;
}
@Value
class ScheduledEvent {
String id;
}