Package org.axonframework.saga.annotation

Source Code of org.axonframework.saga.annotation.AnnotatedSagaManagerTest$EndingEvent

/*
* Copyright (c) 2010-2014. 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.saga.annotation;

import org.axonframework.common.annotation.MetaData;
import org.axonframework.correlation.CorrelationDataHolder;
import org.axonframework.correlation.CorrelationDataProvider;
import org.axonframework.domain.EventMessage;
import org.axonframework.domain.GenericEventMessage;
import org.axonframework.domain.Message;
import org.axonframework.domain.StubDomainEvent;
import org.axonframework.eventhandling.SimpleEventBus;
import org.axonframework.saga.AssociationValue;
import org.axonframework.saga.Saga;
import org.axonframework.saga.repository.inmemory.InMemorySagaRepository;
import org.junit.*;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonMap;
import static org.axonframework.domain.GenericEventMessage.asEventMessage;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

/**
* @author Allard Buijze
*/
public class AnnotatedSagaManagerTest {

    private InMemorySagaRepository sagaRepository;
    private AnnotatedSagaManager manager;

    @Before
    public void setUp() throws Exception {
        CorrelationDataHolder.clear();
        sagaRepository = spy(new InMemorySagaRepository());
        manager = new AnnotatedSagaManager(sagaRepository, new SimpleEventBus(), MyTestSaga.class);
    }

    @After
    public void tearDown() throws Exception {
        CorrelationDataHolder.clear();
    }

    @Test
    public void testCreationPolicy_NoneExists() {
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("123")));
        assertEquals(1, repositoryContents("123", MyTestSaga.class).size());
    }

    @Test
    public void testCreationPolicy_OneAlreadyExists() {
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("123")));
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("123")));
        assertEquals(1, repositoryContents("123", MyTestSaga.class).size());
    }

    @Test
    public void testHandleUnrelatedEvent() {
        manager.handle(new GenericEventMessage("Unrelated"));
        verify(sagaRepository, never()).find(any(Class.class), (AssociationValue) isNull());
    }

    @Test
    public void testCreationPolicy_CreationForced() {
        StartingEvent startingEvent = new StartingEvent("123");
        manager.handle(new GenericEventMessage<StartingEvent>(startingEvent));
        manager.handle(new GenericEventMessage<ForcingStartEvent>(new ForcingStartEvent("123")));
        Set<MyTestSaga> sagas = repositoryContents("123", MyTestSaga.class);
        assertEquals(2, sagas.size());
        for (MyTestSaga saga : sagas) {
            if (saga.getCapturedEvents().contains(startingEvent)) {
                assertEquals(2, saga.getCapturedEvents().size());
            }
            assertTrue(saga.getCapturedEvents().size() >= 1);
        }
    }

    @Test
    public void testCreationPolicy_SagaNotCreated() {
        manager.handle(new GenericEventMessage<MiddleEvent>(new MiddleEvent("123")));
        assertEquals(0, repositoryContents("123", MyTestSaga.class).size());
    }

    @Test
    public void testMostSpecificHandlerEvaluatedFirst() {
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("12")));
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("23")));
        assertEquals(1, repositoryContents("12", MyTestSaga.class).size());
        assertEquals(1, repositoryContents("23", MyTestSaga.class).size());

        manager.handle(new GenericEventMessage<MiddleEvent>(new MiddleEvent("12")));
        manager.handle(new GenericEventMessage<MiddleEvent>(new MiddleEvent("23"), singletonMap("catA", "value")));
        assertEquals(0, repositoryContents("12", MyTestSaga.class).iterator().next().getSpecificHandlerInvocations());
        assertEquals(1, repositoryContents("23", MyTestSaga.class).iterator().next().getSpecificHandlerInvocations());
    }

    @Test
    public void testLifecycle_DestroyedOnEnd() {
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("12")));
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("23")));
        manager.handle(new GenericEventMessage<MiddleEvent>(new MiddleEvent("12")));
        manager.handle(new GenericEventMessage<MiddleEvent>(new MiddleEvent("23"), singletonMap("catA",
                                                                                                "value")));
        assertEquals(1, repositoryContents("12", MyTestSaga.class).size());
        assertEquals(1, repositoryContents("23", MyTestSaga.class).size());
        assertEquals(0, repositoryContents("12", MyTestSaga.class).iterator().next().getSpecificHandlerInvocations());
        assertEquals(1, repositoryContents("23", MyTestSaga.class).iterator().next().getSpecificHandlerInvocations());
        manager.handle(new GenericEventMessage<EndingEvent>(new EndingEvent("12")));
        assertEquals(1, repositoryContents("23", MyTestSaga.class).size());
        assertEquals(0, repositoryContents("12", MyTestSaga.class).size());
        manager.handle(new GenericEventMessage<EndingEvent>(new EndingEvent("23")));
        assertEquals(0, repositoryContents("23", MyTestSaga.class).size());
        assertEquals(0, repositoryContents("12", MyTestSaga.class).size());
    }

    @Test
    public void testNullAssociationValueDoesNotThrowNullPointer() {
        manager.handle(asEventMessage(new StartingEvent(null)));
    }

    @Test
    public void testLifeCycle_ExistingInstanceIgnoresEvent() {
        manager.handle(new GenericEventMessage<StartingEvent>(new StartingEvent("12")));
        manager.handle(new GenericEventMessage<StubDomainEvent>(new StubDomainEvent()));
        assertEquals(1, repositoryContents("12", MyTestSaga.class).size());
        assertEquals(1, repositoryContents("12", MyTestSaga.class).iterator().next().getCapturedEvents().size());
    }

    @Test
    public void testLifeCycle_IgnoredEventDoesNotCreateInstance() {
        manager.handle(new GenericEventMessage<StubDomainEvent>(new StubDomainEvent()));
        assertEquals(0, repositoryContents("12", MyTestSaga.class).size());
    }

    @Test
    public void testSagaTypeTakenIntoConsiderationWhenCheckingForSagasInCreation() throws InterruptedException {
        manager = new AnnotatedSagaManager(sagaRepository, new SimpleEventBus(),
                                           MyOtherTestSaga.class, MyTestSaga.class);

        ExecutorService executorService = Executors.newFixedThreadPool(8);
        for (int i = 0; i < 100; i++) {
            executorService.execute(new HandleEventTask(
                    GenericEventMessage.asEventMessage(new StartingEvent("id" + i))));
            executorService.execute(new HandleEventTask(
                    GenericEventMessage.asEventMessage(new OtherStartingEvent("id" + i))));
        }
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.SECONDS);

        for (int i = 0; i < 100; i++) {
            assertEquals("MyTestSaga missing for id" + i, 1, repositoryContents("id" + i, MyTestSaga.class).size());
            assertEquals("MyOtherTestSaga missing for id" + i, 1, repositoryContents("id" + i, MyOtherTestSaga.class).size());
        }
    }

    @Test
    public void testCorrelationDataReadFromProvider() throws Exception {
        CorrelationDataProvider<? super EventMessage> correlationDataProvider = mock(CorrelationDataProvider.class);
        manager.setCorrelationDataProvider(correlationDataProvider);

        manager.handle(asEventMessage(new StartingEvent("12")).withMetaData(singletonMap("key", "val")));

        verify(correlationDataProvider).correlationDataFor(isA(EventMessage.class));
    }

    @Test
    public void testCorrelationDataReadFromProviders() throws Exception {
        CorrelationDataProvider<Message> correlationDataProvider1 = mock(CorrelationDataProvider.class);
        CorrelationDataProvider<Message> correlationDataProvider2 = mock(CorrelationDataProvider.class);
        manager.setCorrelationDataProviders(asList(correlationDataProvider1, correlationDataProvider2));

        manager.handle(asEventMessage(new StartingEvent("12")).withMetaData(singletonMap("key", "val")));

        verify(correlationDataProvider1).correlationDataFor(isA(EventMessage.class));
        verify(correlationDataProvider2).correlationDataFor(isA(EventMessage.class));
    }

    @Test(timeout = 5000)
    public void testEventForSagaIsHandledWhenSagaIsBeingCreated() throws InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        final CountDownLatch awaitStart = new CountDownLatch(1);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                manager.handle(new GenericEventMessage<StartingEvent>(new SlowStartingEvent("12", awaitStart, 100)));
            }
        });
        awaitStart.await();
        manager.handle(asEventMessage(new MiddleEvent("12")));
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.SECONDS);

        assertEquals(1, repositoryContents("12", MyTestSaga.class).size());
        assertEquals(2, repositoryContents("12", MyTestSaga.class).iterator().next().getCapturedEvents().size());
    }

    @Test
    public void testReturnsVoidTypeWhenManagingNoSagas() throws Exception {
        manager = new AnnotatedSagaManager(sagaRepository);

        assertEquals(void.class, manager.getTargetType());

    }

    private <T extends Saga> Set<T> repositoryContents(String lookupValue, Class<T> sagaType) {
        final Set<String> identifiers = sagaRepository.find(sagaType, new AssociationValue("myIdentifier",
                                                                                           lookupValue));
        Set<T> sagas = new HashSet<T>();
        for (String identifier : identifiers) {
            sagas.add((T) sagaRepository.load(identifier));
        }
        return sagas;
    }

    public static class MyOtherTestSaga extends AbstractAnnotatedSaga {

        @StartSaga
        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSomeEvent(OtherStartingEvent event) throws InterruptedException {
        }
    }

    public static class MyTestSaga extends AbstractAnnotatedSaga {

        private static final long serialVersionUID = -1562911263884220240L;
        private List<Object> capturedEvents = new LinkedList<Object>();
        private int specificHandlerInvocations = 0;

        @StartSaga
        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSomeEvent(StartingEvent event) throws InterruptedException {
            capturedEvents.add(event);
        }

        @StartSaga
        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSomeEvent(SlowStartingEvent event) throws InterruptedException {
            event.getStartCdl().countDown();
            capturedEvents.add(event);
            Thread.sleep(event.getDuration());
        }

        @StartSaga(forceNew = true)
        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSomeEvent(ForcingStartEvent event) {
            capturedEvents.add(event);
        }

        @EndSaga
        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSomeEvent(EndingEvent event) {
            capturedEvents.add(event);
        }

        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleMiddleEvent(MiddleEvent event) {
            capturedEvents.add(event);
        }

        @SagaEventHandler(associationProperty = "myIdentifier")
        public void handleSpecificMiddleEvent(MiddleEvent event, @MetaData(value = "catA", required = true) String category) {
            // this handler is more specific, but requires meta data that not all events might have
            capturedEvents.add(event);
            specificHandlerInvocations++;
        }

        public List<Object> getCapturedEvents() {
            return capturedEvents;
        }

        public int getSpecificHandlerInvocations() {
            return specificHandlerInvocations;
        }
    }

    public static abstract class MyIdentifierEvent {

        private String myIdentifier;

        protected MyIdentifierEvent(String myIdentifier) {
            this.myIdentifier = myIdentifier;
        }

        public String getMyIdentifier() {
            return myIdentifier;
        }
    }

    public static class StartingEvent extends MyIdentifierEvent {

        protected StartingEvent(String myIdentifier) {
            super(myIdentifier);
        }
    }

    public static class OtherStartingEvent extends MyIdentifierEvent {

        private final CountDownLatch countDownLatch;

        protected OtherStartingEvent(String myIdentifier) {
            this(myIdentifier, null);
        }

        public OtherStartingEvent(String id, CountDownLatch countDownLatch) {
            super(id);
            this.countDownLatch = countDownLatch;
        }
    }

    public static class SlowStartingEvent extends StartingEvent {


        private final CountDownLatch startCdl;
        private final long duration;

        protected SlowStartingEvent(String myIdentifier, CountDownLatch startCdl, long duration) {
            super(myIdentifier);
            this.startCdl = startCdl;
            this.duration = duration;
        }

        public long getDuration() {
            return duration;
        }

        public CountDownLatch getStartCdl() {
            return startCdl;
        }
    }

    public static class ForcingStartEvent extends MyIdentifierEvent {

        protected ForcingStartEvent(String myIdentifier) {
            super(myIdentifier);
        }
    }

    public static class EndingEvent extends MyIdentifierEvent {

        protected EndingEvent(String myIdentifier) {
            super(myIdentifier);
        }
    }

    public static class MiddleEvent extends MyIdentifierEvent {

        protected MiddleEvent(String myIdentifier) {
            super(myIdentifier);
        }
    }

    private class HandleEventTask implements Runnable {

        private final EventMessage<?> eventMessage;

        public HandleEventTask(EventMessage<?> eventMessage) {
            this.eventMessage = eventMessage;
        }

        @Override
        public void run() {
            manager.handle(eventMessage);
        }
    }
}
TOP

Related Classes of org.axonframework.saga.annotation.AnnotatedSagaManagerTest$EndingEvent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.