Package org.axonframework.repository

Source Code of org.axonframework.repository.LockingRepositoryTest$InMemoryLockingRepository

/*
* Copyright (c) 2010-2012. 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.repository;

import org.axonframework.domain.AggregateRoot;
import org.axonframework.domain.DomainEventMessage;
import org.axonframework.domain.EventMessage;
import org.axonframework.domain.StubAggregate;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.unitofwork.CurrentUnitOfWork;
import org.axonframework.unitofwork.DefaultUnitOfWork;
import org.axonframework.unitofwork.SaveAggregateCallback;
import org.axonframework.unitofwork.UnitOfWork;
import org.axonframework.unitofwork.UnitOfWorkListenerAdapter;
import org.junit.*;
import org.mockito.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

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

    private LockingRepository<StubAggregate> testSubject;
    private EventBus mockEventBus;
    private LockManager lockManager;

    @Before
    public void setUp() {
        mockEventBus = mock(EventBus.class);
        lockManager = spy(new OptimisticLockManager());
        testSubject = new InMemoryLockingRepository(lockManager);
        testSubject.setEventBus(mockEventBus);
        testSubject = spy(testSubject);

        // some UoW is started somewhere, but not shutdown in the same test.
        while (CurrentUnitOfWork.isStarted()) {
            CurrentUnitOfWork.get().rollback();
        }
    }

    @Test
    public void testStoreNewAggregate() {
        DefaultUnitOfWork.startAndGet();
        StubAggregate aggregate = new StubAggregate();
        aggregate.doSomething();
        testSubject.add(aggregate);
        CurrentUnitOfWork.commit();

        verify(lockManager).obtainLock(aggregate.getIdentifier());
        verify(mockEventBus).publish(isA(DomainEventMessage.class));
    }

    @Test
    public void testLoadAndStoreAggregate() {
        DefaultUnitOfWork.startAndGet();
        StubAggregate aggregate = new StubAggregate();
        aggregate.doSomething();
        testSubject.add(aggregate);
        verify(lockManager).obtainLock(aggregate.getIdentifier());
        CurrentUnitOfWork.commit();
        verify(lockManager).releaseLock(aggregate.getIdentifier());
        reset(lockManager);

        DefaultUnitOfWork.startAndGet();
        StubAggregate loadedAggregate = testSubject.load(aggregate.getIdentifier(), 0L);
        verify(lockManager).obtainLock(aggregate.getIdentifier());

        loadedAggregate.doSomething();
        CurrentUnitOfWork.commit();

        InOrder inOrder = inOrder(lockManager);
        inOrder.verify(lockManager, atLeastOnce()).validateLock(loadedAggregate);
        verify(mockEventBus, times(2)).publish(any(DomainEventMessage.class));
        inOrder.verify(lockManager).releaseLock(loadedAggregate.getIdentifier());
    }

    @SuppressWarnings({"ThrowableInstanceNeverThrown"})
    @Test
    public void testLoadAndStoreAggregate_LockReleasedOnException() {
        DefaultUnitOfWork.startAndGet();
        StubAggregate aggregate = new StubAggregate();
        aggregate.doSomething();
        testSubject.add(aggregate);
        verify(lockManager).obtainLock(aggregate.getIdentifier());
        CurrentUnitOfWork.commit();
        verify(lockManager).releaseLock(aggregate.getIdentifier());
        reset(lockManager);

        DefaultUnitOfWork.startAndGet();
        StubAggregate loadedAggregate = testSubject.load(aggregate.getIdentifier(), 0L);
        verify(lockManager).obtainLock(aggregate.getIdentifier());

        CurrentUnitOfWork.get().registerListener(new UnitOfWorkListenerAdapter() {
            @Override
            public void onPrepareCommit(UnitOfWork unitOfWork, Set<AggregateRoot> aggregateRoots,
                                        List<EventMessage> events) {
                throw new RuntimeException("Mock Exception");
            }
        });
        try {
            CurrentUnitOfWork.commit();
            fail("Expected exception to be thrown");
        } catch (RuntimeException e) {
            assertEquals("Mock Exception", e.getMessage());
        }

        // make sure the lock is released
        verify(lockManager).releaseLock(loadedAggregate.getIdentifier());
    }

    @SuppressWarnings({"ThrowableInstanceNeverThrown"})
    @Test
    public void testLoadAndStoreAggregate_PessimisticLockReleasedOnException() {
        lockManager = spy(new PessimisticLockManager());
        testSubject = new InMemoryLockingRepository(lockManager);
        testSubject.setEventBus(mockEventBus);
        testSubject = spy(testSubject);

        // we do the same test, but with a pessimistic lock, which has a different way of "re-acquiring" a lost lock
        DefaultUnitOfWork.startAndGet();
        StubAggregate aggregate = new StubAggregate();
        aggregate.doSomething();
        testSubject.add(aggregate);
        verify(lockManager).obtainLock(aggregate.getIdentifier());
        CurrentUnitOfWork.commit();
        verify(lockManager).releaseLock(aggregate.getIdentifier());
        reset(lockManager);

        DefaultUnitOfWork.startAndGet();
        StubAggregate loadedAggregate = testSubject.load(aggregate.getIdentifier(), 0L);
        verify(lockManager).obtainLock(aggregate.getIdentifier());

        CurrentUnitOfWork.get().registerListener(new UnitOfWorkListenerAdapter() {
            @Override
            public void onPrepareCommit(UnitOfWork unitOfWork, Set<AggregateRoot> aggregateRoots,
                                        List<EventMessage> events) {
                throw new RuntimeException("Mock Exception");
            }
        });

        try {
            CurrentUnitOfWork.commit();
            fail("Expected exception to be thrown");
        } catch (RuntimeException e) {
            assertEquals("Mock Exception", e.getMessage());
        }

        // make sure the lock is released
        verify(lockManager).releaseLock(loadedAggregate.getIdentifier());
    }

    @Test
    public void testSaveAggregate_RefusedDueToLackingLock() {
        lockManager = spy(new PessimisticLockManager());
        testSubject = new InMemoryLockingRepository(lockManager);
        testSubject.setEventBus(mockEventBus);
        testSubject = spy(testSubject);
        EventBus eventBus = mock(EventBus.class);

        DefaultUnitOfWork.startAndGet();
        StubAggregate aggregate = new StubAggregate();
        aggregate.doSomething();
        testSubject.add(aggregate);
        CurrentUnitOfWork.commit();

        DefaultUnitOfWork.startAndGet();
        StubAggregate loadedAggregate = testSubject.load(aggregate.getIdentifier(), 0L);
        loadedAggregate.doSomething();
        CurrentUnitOfWork.commit();

        // this tricks the UnitOfWork to save this aggregate, without loading it.
        DefaultUnitOfWork.startAndGet();
        CurrentUnitOfWork.get().registerAggregate(loadedAggregate,
                                                  eventBus,
                                                  new SaveAggregateCallback<StubAggregate>() {
                                                      @Override
                                                      public void save(StubAggregate aggregate) {
                                                          testSubject.doSave(aggregate);
                                                      }
                                                  });
        loadedAggregate.doSomething();
        try {
            CurrentUnitOfWork.commit();
            fail("This should have failed due to lacking lock");
        } catch (ConcurrencyException e) {
            // that's ok
        }
    }

    static class InMemoryLockingRepository extends LockingRepository<StubAggregate> {

        private Map<Object, StubAggregate> store = new HashMap<Object, StubAggregate>();
        private int saveCount;

        public InMemoryLockingRepository(LockManager lockManager) {
            super(StubAggregate.class, lockManager);
        }

        @Override
        protected void doSaveWithLock(StubAggregate aggregate) {
            store.put(aggregate.getIdentifier(), aggregate);
            saveCount++;
        }

        @Override
        protected void doDeleteWithLock(StubAggregate aggregate) {
            store.remove(aggregate.getIdentifier());
            saveCount++;
        }

        @Override
        protected StubAggregate doLoad(Object aggregateIdentifier, Long expectedVersion) {
            return store.get(aggregateIdentifier);
        }

        public int getSaveCount() {
            return saveCount;
        }

        public void resetSaveCount() {
            saveCount = 0;
        }
    }
}
TOP

Related Classes of org.axonframework.repository.LockingRepositoryTest$InMemoryLockingRepository

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.