/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2014 Boundless * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.cluster.hazelcast; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import org.easymock.IAnswer; import org.easymock.IExpectationSetters; import org.geoserver.catalog.CatalogInfo; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.Info; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.catalog.event.CatalogAddEvent; import org.geoserver.catalog.event.CatalogEvent; import org.geoserver.catalog.event.CatalogListener; import org.geoserver.catalog.event.CatalogPostModifyEvent; import org.geoserver.catalog.event.CatalogRemoveEvent; import org.geoserver.catalog.impl.DataStoreInfoImpl; import org.geoserver.cluster.ConfigChangeEvent; import org.geoserver.cluster.ConfigChangeEvent.Type; import org.geoserver.config.ConfigurationListener; import org.geoserver.config.GeoServerInfo; import org.geoserver.config.LoggingInfo; import org.geoserver.config.ServiceInfo; import org.geoserver.config.SettingsInfo; import org.hamcrest.integration.EasyMock2Adapter; import org.junit.Before; import org.junit.Test; public class EventHzSynchronizerRecvTest extends HzSynchronizerRecvTest { ConfigurationListener configListener; CatalogListener catListener; @Before public void setUpListeners(){ configListener = createMock(ConfigurationListener.class); catListener = createMock(CatalogListener.class); } Info info(String id) { EasyMock2Adapter.adapt(hasProperty("id", is(id))); return null; } @Override protected HzSynchronizer getSynchronizer() { return new EventHzSynchronizer(cluster, getGeoServer()) { @Override ScheduledExecutorService getNewExecutor() { return getMockExecutor(); } @Override public boolean isStarted(){ return true; } }; } @Test public void testPublishAck() throws Exception { // This is just testStoreDelete with an extra assert to test if the ack was sent DataStoreInfo info; WorkspaceInfo wsInfo; final String storeName = "testStore"; final String storeId = "Store-TEST"; final String storeWorkspace = "Workspace-TEST"; { info = createMock(DataStoreInfo.class); wsInfo = createMock(WorkspaceInfo.class); expect(info.getName()).andStubReturn(storeName); expect(info.getId()).andStubReturn(storeId); expect(info.getWorkspace()).andStubReturn(wsInfo); expect(wsInfo.getId()).andStubReturn(storeWorkspace); expectationTestStoreDelete(info, storeName, storeId, DataStoreInfo.class); } replay(info, wsInfo); ConfigChangeEvent evt = new ConfigChangeEvent(storeId, storeName, DataStoreInfoImpl.class, Type.REMOVE); { sync = getSynchronizer(); sync.initialize(configWatcher); evt.setWorkspaceId(storeWorkspace); // Mock a message coming in from the cluster mockMessage(evt); } waitForSync(); // Did the ack get sent this.assertAcked(evt.getUUID()); verify(info, wsInfo); } @Override protected void expectationTestDisableLayer(LayerInfo info, String layerName, String id) throws Exception { expect(getCatalog().getLayer(id) ).andReturn(info); expectCatalogFire(info, id, Type.MODIFY); } @Override protected void expectationTestStoreDelete(DataStoreInfo info, String storeName, String storeId, Class clazz) throws Exception { expect(getCatalog().getStore(storeId, clazz) ).andStubReturn(null); // It's been deleted so return null expectCatalogFire(info, storeId, Type.REMOVE); } @Override protected void expectationTestFTDelete(FeatureTypeInfo info, String ftName, String ftId, String dsId, Class clazz) throws Exception { expect(getCatalog().getFeatureType(ftId)).andStubReturn(null); // It's been deleted so return null final String id = ftId; expectCatalogGetListeners(); CatalogRemoveEvent catEvent = (CatalogRemoveEvent)catResEvent(id, dsId); // Want to make sure the DS is included catListener.handleRemoveEvent(catEvent);expectLastCall(); } @Override protected void expectationTestContactChange(GeoServerInfo info, String globalId) throws Exception { expect(getGeoServer().getGlobal()).andReturn(info); // TODO: Expect this instead of mocking ConfigurationListener //expect(getGeoServer().fireGlobalPostModified()); configListener.handlePostGlobalChange((GeoServerInfo)info(globalId));expectLastCall(); expectConfigGetListeners(); } @Override public List<Object> myMocks() { List<Object> mocks = new ArrayList<Object>(); mocks.addAll(super.myMocks()); mocks.add(configListener); mocks.add(catListener); return mocks; } @Override protected void expectationTestMultipleChange(GeoServerInfo gsInfo, String globalId, LayerInfo layerInfo, String layerId) throws Exception{ expectationTestContactChange(gsInfo, globalId); expectationTestContactChange(gsInfo, globalId); expectationTestContactChange(gsInfo, globalId); expectationTestDisableLayer(layerInfo, null, layerId); expectationTestDisableLayer(layerInfo, null, layerId); expectationTestContactChange(gsInfo, globalId); expectationTestDisableLayer(layerInfo, null, layerId); expectationTestDisableLayer(layerInfo, null, layerId); } @Override protected void expectationTestTwoAddressChangeNoPause(GeoServerInfo gsInfo, String globalId) throws Exception { expectationTestContactChange(gsInfo, globalId); expectationTestContactChange(gsInfo, globalId); } @Override protected void expectationTestTwoAddressChangeWithPause( GeoServerInfo gsInfo, String globalId) throws Exception { expectationTestContactChange(gsInfo, globalId); expectationTestContactChange(gsInfo, globalId); } @Override protected void expectationTestTwoLayerChangeNoPause(final LayerInfo layerInfo, String layerId) throws Exception { expect(getCatalog().getLayer(layerId) ).andReturn(layerInfo).anyTimes(); expectCatalogFire(layerInfo, layerId, Type.MODIFY).times(2); } @Override protected void expectationTestTwoLayerChangeWithPause(final LayerInfo layerInfo, String layerId) throws Exception { expect(getCatalog().getLayer(layerId) ).andReturn(layerInfo).anyTimes(); expectCatalogFire(layerInfo, layerId, Type.MODIFY).times(2); } @Override protected void expectationTestWorkspaceAdd(final WorkspaceInfo info, String workspaceName, String workspaceId) throws Exception { expect(getCatalog().getWorkspace(workspaceId) ).andReturn(info); expectCatalogFire(info, workspaceId, Type.ADD); } @Override protected void expectationTestChangeSettings(SettingsInfo info, String settingsId, WorkspaceInfo wsInfo, String workspaceId) throws Exception { // TODO: Expect this instead of mocking ConfigurationListener //expect(getGeoServer().fireSettingsPostModified()); configListener.handleSettingsPostModified((SettingsInfo)info(settingsId));expectLastCall(); expectConfigGetListeners(); } @Override protected void expectationTestChangeLogging(LoggingInfo info, String loggingId) throws Exception { // TODO: Expect this instead of mocking ConfigurationListener //expect(getGeoServer().fireLoggingPostModified()); configListener.handlePostLoggingChange((LoggingInfo)info(loggingId));expectLastCall(); expectConfigGetListeners(); } @Override protected void expectationTestChangeService(ServiceInfo info, String serviceId) throws Exception { // TODO: Expect this instead of mocking ConfigurationListener //expect(getGeoServer().fireLoggingPostModified()); configListener.handlePostServiceChange((ServiceInfo)info(serviceId));expectLastCall(); expectConfigGetListeners(); } protected void expectConfigGetListeners(){ expect(getGeoServer().getListeners()).andStubAnswer(new IAnswer<Collection<ConfigurationListener>>() { @Override public Collection<ConfigurationListener> answer() throws Throwable { return Arrays.asList(sync, configListener); }}); } protected void expectCatalogGetListeners(){ expect(getCatalog().getListeners()).andStubAnswer(new IAnswer<Collection<CatalogListener>>() { @Override public Collection<CatalogListener> answer() throws Throwable { return Arrays.asList(sync, catListener); }}); } CatalogEvent catEvent(final CatalogInfo info) { EasyMock2Adapter.adapt(hasProperty("source", is(info))); return null; } CatalogEvent catEvent(final String id) { EasyMock2Adapter.adapt(hasProperty("source", hasProperty("id", is(id)))); return null; } /** * Matches a Catalog Event that has a source with the given ID, and a Store property, the value of which has the given ID. * @param id id of the source * @param storeId id of the source's store */ CatalogEvent catResEvent(final String id, final String storeId) { EasyMock2Adapter.adapt(hasProperty("source", allOf(hasProperty("id", is(id)), hasProperty("store", hasProperty("id", is(storeId)))))); return null; } protected IExpectationSetters<Object> expectCatalogFire(final CatalogInfo info, final String id, final ConfigChangeEvent.Type type){ expectCatalogGetListeners(); switch(type) { case ADD: catListener.handleAddEvent((CatalogAddEvent)catEvent(info)); break; case MODIFY: catListener.handlePostModifyEvent((CatalogPostModifyEvent)catEvent(info)); break; case REMOVE: catListener.handleRemoveEvent((CatalogRemoveEvent)catEvent(id)); break; } return expectLastCall(); } /* protected IExpectationSetters<Object> expectCatalogFire(final CatalogInfo info, final String id, final ConfigChangeEvent.Type type){ switch(type) { case ADD: getCatalog().fireAdded((CatalogInfo)info(id)); break; case MODIFY: getCatalog().firePostModified((CatalogInfo)info(id)); break; case REMOVE: getCatalog().fireRemoved((CatalogInfo)info(id)); break; } return expectLastCall().andAnswer(new IAnswer<Object>() { @Override public Object answer() throws Throwable { switch(type) { case ADD: CatalogAddEventImpl addEvt = new CatalogAddEventImpl(); addEvt.setSource(info); sync.handleAddEvent(addEvt); break; case MODIFY: CatalogPostModifyEventImpl modEvt = new CatalogPostModifyEventImpl(); modEvt.setSource(info); sync.handlePostModifyEvent(modEvt); break; case REMOVE: CatalogRemoveEventImpl remEvt = new CatalogRemoveEventImpl(); remEvt.setSource(info); sync.handleRemoveEvent(remEvt); break; } return null; }}); } */ }