/* * HA-JDBC: High-Availability JDBC * Copyright (C) 2014 Paul Ferraro * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.hajdbc.state.distributed; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import java.util.Map; import java.util.UUID; import net.sf.hajdbc.Database; import net.sf.hajdbc.DatabaseCluster; import net.sf.hajdbc.ExceptionType; import net.sf.hajdbc.distributed.CommandDispatcherFactory; import net.sf.hajdbc.distributed.jgroups.JGroupsCommandDispatcherFactory; import net.sf.hajdbc.durability.Durability; import net.sf.hajdbc.durability.Durability.Phase; import net.sf.hajdbc.durability.InvocationEvent; import net.sf.hajdbc.durability.InvocationEventImpl; import net.sf.hajdbc.durability.InvokerEvent; import net.sf.hajdbc.durability.InvokerEventImpl; import net.sf.hajdbc.durability.InvokerResult; import net.sf.hajdbc.durability.InvokerResultImpl; import net.sf.hajdbc.state.DatabaseEvent; import net.sf.hajdbc.state.StateManager; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Unit test for {@link DistributedStateManager}. * @author Paul Ferraro */ public class DistributedStateManagerTestCase { private DatabaseCluster<Void, Database<Void>> cluster1 = mock(DatabaseCluster.class); private DatabaseCluster<Void, Database<Void>> cluster2 = mock(DatabaseCluster.class); private StateManager localManager1 = mock(StateManager.class); private StateManager localManager2 = mock(StateManager.class); private Durability<Void, Database<Void>> durability1 = mock(Durability.class); private Durability<Void, Database<Void>> durability2 = mock(Durability.class); private DistributedStateManager<Void, Database<Void>> manager1; private DistributedStateManager<Void, Database<Void>> manager2; @Before public void init() throws Exception { String id = "cluster"; when(this.cluster1.getId()).thenReturn(id); when(this.cluster2.getId()).thenReturn(id); when(this.cluster1.getStateManager()).thenReturn(this.localManager1); when(this.cluster2.getStateManager()).thenReturn(this.localManager2); when(this.cluster1.getDurability()).thenReturn(this.durability1); when(this.cluster2.getDurability()).thenReturn(this.durability2); CommandDispatcherFactory dispatcherFactory1 = createCommandDispatcherFactory("node1"); CommandDispatcherFactory dispatcherFactory2 = createCommandDispatcherFactory("node2"); this.manager1 = new DistributedStateManager<>(this.cluster1, dispatcherFactory1); this.manager1.start(); verify(this.localManager1).start(); this.manager2 = new DistributedStateManager<>(this.cluster2, dispatcherFactory2); this.manager2.start(); verify(this.localManager2).start(); } static CommandDispatcherFactory createCommandDispatcherFactory(String name) { JGroupsCommandDispatcherFactory factory = new JGroupsCommandDispatcherFactory(); factory.setName(name); factory.setStack("fast.xml"); return factory; } @After public void destroy() { this.manager1.stop(); verify(this.localManager1).stop(); this.manager1 = null; this.manager2.stop(); verify(this.localManager2).stop(); this.manager2 = null; } @Test public void activate() { String databaseId = "test"; Database<Void> database = mock(Database.class); when(database.getId()).thenReturn(databaseId); DatabaseEvent event = new DatabaseEvent(database); when(this.cluster2.getDatabase(databaseId)).thenReturn(database); this.manager1.activated(event); verify(this.localManager1).activated(event); verify(this.cluster2).activate(database, this.localManager2); when(this.cluster1.getDatabase(databaseId)).thenReturn(database); this.manager2.activated(event); verify(this.localManager2).activated(event); verify(this.cluster1).activate(database, this.localManager1); } @Test public void deactivate() { String databaseId = "test"; Database<Void> database = mock(Database.class); when(database.getId()).thenReturn(databaseId); DatabaseEvent event = new DatabaseEvent(database); when(this.cluster2.getDatabase(databaseId)).thenReturn(database); this.manager1.deactivated(event); verify(this.localManager1).deactivated(event); verify(this.cluster2).deactivate(database, this.localManager2); when(this.cluster1.getDatabase(databaseId)).thenReturn(database); this.manager2.deactivated(event); verify(this.localManager2).deactivated(event); verify(this.cluster1).deactivate(database, this.localManager1); } @Test public void recover() { Map<InvocationEvent, Map<String, InvokerEvent>> invocations = mock(Map.class); when(this.localManager1.recover()).thenReturn(invocations); Map<InvocationEvent, Map<String, InvokerEvent>> result = this.manager1.recover(); assertSame(invocations, result); when(this.localManager2.recover()).thenReturn(invocations); result = this.manager2.recover(); assertSame(invocations, result); } @Test public void durability() { Object tx = UUID.randomUUID(); Phase phase = Phase.COMMIT; ExceptionType exceptionType = ExceptionType.SQL; InvocationEvent invocationEvent = new InvocationEventImpl(tx, phase, exceptionType); this.manager1.beforeInvocation(invocationEvent); verify(this.localManager1).beforeInvocation(invocationEvent); Map<InvocationEvent, Map<String, InvokerEvent>> invocations = this.manager2.getRemoteInvokers(this.manager1); assertEquals(1, invocations.size()); Map<String, InvokerEvent> invokers = invocations.get(invocationEvent); assertNotNull(invokers); assertEquals(0, invokers.size()); String databaseId = "test"; InvokerEvent invokerEvent = new InvokerEventImpl(tx, phase, databaseId); this.manager1.beforeInvoker(invokerEvent); verify(this.localManager1).beforeInvoker(invokerEvent); invocations = this.manager2.getRemoteInvokers(this.manager1); assertEquals(1, invocations.size()); invokers = invocations.get(invocationEvent); assertNotNull(invokers); assertEquals(1, invokers.size()); assertEquals(invokerEvent, invokers.get(databaseId)); InvokerResult result = new InvokerResultImpl("value"); invokerEvent.setResult(result); this.manager1.afterInvoker(invokerEvent); verify(this.localManager1).afterInvoker(invokerEvent); invocations = this.manager2.getRemoteInvokers(this.manager1); assertEquals(1, invocations.size()); invokers = invocations.get(invocationEvent); assertNotNull(invokers); assertEquals(1, invokers.size()); InvokerEvent resultEvent = invokers.get(databaseId); assertEquals(invokerEvent, resultEvent); assertEquals(result.getValue(), resultEvent.getResult().getValue()); this.manager1.afterInvocation(invocationEvent); verify(this.localManager1).afterInvocation(invocationEvent); invocations = this.manager2.getRemoteInvokers(this.manager1); assertEquals(0, invocations.size()); } }