/* * Copyright Terracotta, Inc. * * 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.ehcache.clustered.server; import org.ehcache.clustered.common.ServerSideConfiguration; import org.ehcache.clustered.common.ServerSideConfiguration.Pool; import org.ehcache.clustered.common.internal.ClusterTierManagerConfiguration; import org.ehcache.clustered.common.internal.exceptions.DestroyInProgressException; import org.ehcache.clustered.common.internal.exceptions.InvalidServerSideConfigurationException; import org.ehcache.clustered.common.internal.messages.EhcacheEntityMessage; import org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse; import org.ehcache.clustered.common.internal.messages.EhcacheEntityResponse.Failure; import org.ehcache.clustered.common.internal.messages.EhcacheResponseType; import org.ehcache.clustered.common.internal.messages.LifeCycleMessageFactory; import org.ehcache.clustered.server.management.Management; import org.ehcache.clustered.server.state.EhcacheStateService; import org.ehcache.clustered.server.state.config.EhcacheStateServiceConfig; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.terracotta.entity.ClientCommunicator; import org.terracotta.entity.ClientDescriptor; import org.terracotta.entity.ConfigurationException; import org.terracotta.entity.IEntityMessenger; import org.terracotta.entity.ServiceConfiguration; import org.terracotta.entity.ServiceRegistry; import org.terracotta.management.service.monitoring.ActiveEntityMonitoringServiceConfiguration; import org.terracotta.management.service.monitoring.ConsumerManagementRegistryConfiguration; import org.terracotta.offheapresource.OffHeapResource; import org.terracotta.offheapresource.OffHeapResourceIdentifier; import org.terracotta.offheapresource.OffHeapResources; import org.terracotta.offheapstore.util.MemoryUnit; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; public class ClusterTierManagerActiveEntityTest { private static final LifeCycleMessageFactory MESSAGE_FACTORY = new LifeCycleMessageFactory(); private static final UUID CLIENT_ID = UUID.randomUUID(); private static final KeySegmentMapper DEFAULT_MAPPER = new KeySegmentMapper(16); private static final Management MANAGEMENT = mock(Management.class); private ClusterTierManagerConfiguration blankConfiguration = new ClusterTierManagerConfiguration("identifier", new ServerSideConfigBuilder().build()); @Before public void setClientId() { MESSAGE_FACTORY.setClientId(CLIENT_ID); } @Test(expected = ConfigurationException.class) public void testConfigNull() throws Exception { new ClusterTierManagerActiveEntity(null, null, null, null); } /** * Ensures that a client connection is properly tracked. */ @Test public void testConnected() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); final Set<ClientDescriptor> connectedClients = activeEntity.getConnectedClients(); assertThat(connectedClients, is(equalTo(Collections.singleton(client)))); } @Test public void testConnectedAgain() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), is(equalTo(Collections.singleton(client)))); activeEntity.connected(client); final Set<ClientDescriptor> connectedClients = activeEntity.getConnectedClients(); assertThat(connectedClients, is(equalTo(Collections.singleton(client)))); } @Test public void testConnectedSecond() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); ClientDescriptor client2 = new TestClientDescriptor(); activeEntity.connected(client2); final Set<ClientDescriptor> connectedClients = activeEntity.getConnectedClients(); assertThat(connectedClients, containsInAnyOrder(client, client2)); } /** * Ensures a disconnect for a non-connected client does not throw. */ @Test public void testDisconnectedNotConnected() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.disconnected(client); // Not expected to fail ... } /** * Ensures the disconnect of a connected client is properly tracked. */ @Test public void testDisconnected() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); activeEntity.disconnected(client); assertThat(activeEntity.getConnectedClients().isEmpty(), is(true)); } /** * Ensures the disconnect of a connected client is properly tracked and does not affect others. */ @Test public void testDisconnectedSecond() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); ClientDescriptor client2 = new TestClientDescriptor(); activeEntity.connected(client2); assertThat(activeEntity.getConnectedClients(), containsInAnyOrder(client, client2)); activeEntity.disconnected(client); assertThat(activeEntity.getConnectedClients(), is(equalTo(Collections.singleton(client2)))); } /** * Ensures basic shared resource pool configuration. */ @Test public void testConfigure() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertThat(registry.getStoreManagerService().getSharedResourcePoolIds(), containsInAnyOrder("primary", "secondary")); assertThat(registry.getResource("serverResource1").getUsed(), is(MemoryUnit.MEGABYTES.toBytes(4L))); assertThat(registry.getResource("serverResource2").getUsed(), is(MemoryUnit.MEGABYTES.toBytes(8L))); assertThat(registry.getResource("defaultServerResource").getUsed(), is(0L)); assertThat(registry.getStoreManagerService().getStores(), is(Matchers.<String>empty())); } /** * Ensure configuration fails when specifying non-existent resource. */ @Test public void testConfigureMissingPoolResource() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("serverResource1", 32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 64, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) // missing on 'server' .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); try { new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); fail("Entity creation should have failed"); } catch (ConfigurationException e) { assertThat(e.getMessage(), containsString("Non-existent server side resource")); } assertThat(registry.getStoreManagerService().getSharedResourcePoolIds(), is(Matchers.<String>empty())); assertThat(registry.getResource("serverResource1").getUsed(), is(0L)); assertThat(registry.getResource("serverResource2"), is(nullValue())); assertThat(registry.getResource("defaultServerResource").getUsed(), is(0L)); assertThat(registry.getStoreManagerService().getStores(), is(Matchers.<String>empty())); } /** * Ensure configuration fails when specifying non-existent default resource. */ @Test public void testConfigureMissingDefaultResource() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("serverResource1", 32, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 32, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("idenitifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); try { new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); fail("Entity creation should have failed"); } catch (ConfigurationException e) { assertThat(e.getMessage(), containsString("Default server resource")); } assertThat(registry.getStoreManagerService().getSharedResourcePoolIds(), is(Matchers.<String>empty())); assertThat(registry.getResource("serverResource1").getUsed(), is(0L)); assertThat(registry.getResource("serverResource2").getUsed(), is(0L)); assertThat(registry.getResource("defaultServerResource"), is(nullValue())); assertThat(registry.getStoreManagerService().getStores(), is(Matchers.<String>empty())); } @Test public void testConfigureLargeSharedPool() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("defaultServerResource", 64, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 32, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 32, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .sharedPool("tooBig", "serverResource2", 64, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); try { new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); fail("Entity creation should have failed"); } catch (ConfigurationException e) { assertThat(e.getMessage(), containsString("resources to allocate")); } final Set<String> poolIds = registry.getStoreManagerService().getSharedResourcePoolIds(); assertThat(poolIds, is(Matchers.<String>empty())); assertThat(registry.getResource("serverResource1").getUsed(), is(0L)); assertThat(registry.getResource("serverResource2").getUsed(), is(0L)); assertThat(registry.getResource("defaultServerResource").getUsed(), is(0L)); assertThat(registry.getStoreManagerService().getStores(), is(Matchers.<String>empty())); } @Test public void testValidate2Clients() throws Exception { ServerSideConfiguration serverSideConfig = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("idenitifer", serverSideConfig); OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertSuccess(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(serverSideConfig))); UUID client2Id = UUID.randomUUID(); ClientDescriptor client2 = new TestClientDescriptor(); activeEntity.connected(client2); assertThat(activeEntity.getConnectedClients(), containsInAnyOrder(client, client2)); MESSAGE_FACTORY.setClientId(client2Id); assertSuccess(activeEntity.invoke(client2, MESSAGE_FACTORY.validateStoreManager(serverSideConfig))); } @Test public void testValidate1Client() throws Exception { ServerSideConfiguration serverSideConfig = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfig); OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); activeEntity.disconnected(client); assertThat(activeEntity.getConnectedClients(), is(Matchers.<ClientDescriptor>empty())); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertSuccess(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(serverSideConfig))); } @Test public void testValidateAfterConfigure() throws Exception { ServerSideConfiguration serverSideConfig = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfig); OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertSuccess(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(serverSideConfig))); } @Test public void testValidateExtraResource() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertFailure(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .sharedPool("tertiary", "serverResource3", 8, MemoryUnit.MEGABYTES) // extra .build())), InvalidServerSideConfigurationException.class, "Pool names not equal."); } @Test public void testValidateNoDefaultResource() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); ServerSideConfiguration serverSideConfiguration = new ServerSideConfigBuilder() .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", serverSideConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertThat(activeEntity.getConnectedClients(), contains(client)); assertFailure(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build())), InvalidServerSideConfigurationException.class, "Default resource not aligned"); } @Test public void testDestroyEmpty() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); activeEntity.destroy(); } @Test public void testValidateIdenticalConfiguration() throws Exception { ServerSideConfiguration configureConfig = new ServerSideConfigBuilder() .defaultResource("primary-server-resource") .sharedPool("foo", null, 8, MemoryUnit.MEGABYTES) .sharedPool("bar", "secondary-server-resource", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", configureConfig); ServerSideConfiguration validateConfig = new ServerSideConfigBuilder() .defaultResource("primary-server-resource") .sharedPool("foo", null, 8, MemoryUnit.MEGABYTES) .sharedPool("bar", "secondary-server-resource", 8, MemoryUnit.MEGABYTES) .build(); OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("primary-server-resource", 16, MemoryUnit.MEGABYTES); registry.addResource("secondary-server-resource", 16, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor validator = new TestClientDescriptor(); activeEntity.connected(validator); assertThat(activeEntity.invoke(validator, MESSAGE_FACTORY.validateStoreManager(validateConfig)).getResponseType(), is(EhcacheResponseType.SUCCESS)); } @Test public void testValidateSharedPoolNamesDifferent() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 64, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 32, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 32, MemoryUnit.MEGABYTES); ServerSideConfiguration configure = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", configure); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor validator = new TestClientDescriptor(); activeEntity.connected(validator); ServerSideConfiguration validate = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("ternary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); assertFailure(activeEntity.invoke(validator, MESSAGE_FACTORY.validateStoreManager(validate)), InvalidServerSideConfigurationException.class, "Pool names not equal."); } @Test public void testValidateDefaultResourceNameDifferent() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); ServerSideConfiguration configure = new ServerSideConfigBuilder() .defaultResource("defaultServerResource1") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", configure); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor validator = new TestClientDescriptor(); activeEntity.connected(validator); ServerSideConfiguration validate = new ServerSideConfigBuilder() .defaultResource("defaultServerResource2") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); assertFailure(activeEntity.invoke(validator, MESSAGE_FACTORY.validateStoreManager(validate)), InvalidServerSideConfigurationException.class, "Default resource not aligned."); } @Test public void testValidateClientSharedPoolSizeTooBig() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(64, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 32, MemoryUnit.MEGABYTES); ServerSideConfiguration configure = new ServerSideConfigBuilder() .defaultResource("defaultServerResource1") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 32, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", configure); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor validator = new TestClientDescriptor(); activeEntity.connected(validator); ServerSideConfiguration validate = new ServerSideConfigBuilder() .defaultResource("defaultServerResource1") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 36, MemoryUnit.MEGABYTES) .build(); assertFailure(activeEntity.invoke(validator, MESSAGE_FACTORY.validateStoreManager(validate)),InvalidServerSideConfigurationException.class, "Pool 'secondary' not equal."); } @Test public void testValidateSecondClientInheritsFirstClientConfig() throws Exception { OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(32, MemoryUnit.MEGABYTES); registry.addResource("defaultServerResource", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); registry.addResource("serverResource2", 8, MemoryUnit.MEGABYTES); ServerSideConfiguration initialConfiguration = new ServerSideConfigBuilder() .defaultResource("defaultServerResource") .sharedPool("primary", "serverResource1", 4, MemoryUnit.MEGABYTES) .sharedPool("secondary", "serverResource2", 8, MemoryUnit.MEGABYTES) .build(); ClusterTierManagerConfiguration configuration = new ClusterTierManagerConfiguration("identifier", initialConfiguration); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(configuration, registry, DEFAULT_MAPPER)); ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, configuration, ehcacheStateService, MANAGEMENT); ClientDescriptor validator = new TestClientDescriptor(); activeEntity.connected(validator); assertSuccess(activeEntity.invoke(validator, MESSAGE_FACTORY.validateStoreManager(null))); } @Test public void testInvalidMessageThrowsError() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); try { activeEntity.invoke(client, new InvalidMessage()); fail("Invalid message should result in AssertionError"); } catch (AssertionError e) { assertThat(e.getMessage(), containsString("Unsupported")); } } @Test public void testPrepareForDestroy() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); activeEntity.invoke(client, MESSAGE_FACTORY.prepareForDestroy()); try { ehcacheStateService.validate(null); fail("DestroyInProgressException expected"); } catch (DestroyInProgressException e) { assertThat(e.getMessage(), containsString("in progress for destroy")); } } @Test public void testPrepareForDestroyInProgress() throws Exception { final OffHeapIdentifierRegistry registry = new OffHeapIdentifierRegistry(); registry.addResource("serverResource1", 8, MemoryUnit.MEGABYTES); EhcacheStateService ehcacheStateService = registry.getService(new EhcacheStateServiceConfig(blankConfiguration, registry, DEFAULT_MAPPER)); ehcacheStateService.prepareForDestroy(); final ClusterTierManagerActiveEntity activeEntity = new ClusterTierManagerActiveEntity(registry, blankConfiguration, ehcacheStateService, MANAGEMENT); ClientDescriptor client = new TestClientDescriptor(); activeEntity.connected(client); assertFailure(activeEntity.invoke(client, MESSAGE_FACTORY.validateStoreManager(null)), DestroyInProgressException.class, "in progress for destroy"); } private void assertSuccess(EhcacheEntityResponse response) throws Exception { if (!response.equals(EhcacheEntityResponse.Success.INSTANCE)) { throw ((Failure) response).getCause(); } } private void assertFailure(EhcacheEntityResponse response, Class<? extends Exception> expectedException, String expectedMessageContent) { assertThat(response.getResponseType(), is(EhcacheResponseType.FAILURE)); Exception cause = ((Failure) response).getCause(); assertThat(cause, is(instanceOf(expectedException))); assertThat(cause.getMessage(), containsString(expectedMessageContent)); } private static Pool pool(String resourceName, int poolSize, MemoryUnit unit) { return new Pool(unit.toBytes(poolSize), resourceName); } private static final class ServerSideConfigBuilder { private final Map<String, Pool> pools = new HashMap<String, Pool>(); private String defaultServerResource; ServerSideConfigBuilder sharedPool(String poolName, String resourceName, int size, MemoryUnit unit) { pools.put(poolName, pool(resourceName, size, unit)); return this; } ServerSideConfigBuilder defaultResource(String resourceName) { this.defaultServerResource = resourceName; return this; } ServerSideConfiguration build() { if (defaultServerResource == null) { return new ServerSideConfiguration(pools); } else { return new ServerSideConfiguration(defaultServerResource, pools); } } } private static final class TestClientDescriptor implements ClientDescriptor { private static final AtomicInteger counter = new AtomicInteger(0); private final int clientId = counter.incrementAndGet(); @Override public String toString() { return "TestClientDescriptor[" + clientId + "]"; } } /** * Provides a {@link ServiceRegistry} for off-heap resources. This is a "server-side" object. */ private static final class OffHeapIdentifierRegistry implements ServiceRegistry { private final long offHeapSize; private EhcacheStateServiceImpl storeManagerService; private IEntityMessenger entityMessenger; private ClientCommunicator clientCommunicator; private final Map<OffHeapResourceIdentifier, TestOffHeapResource> pools = new HashMap<OffHeapResourceIdentifier, TestOffHeapResource>(); /** * Instantiate an "open" {@code ServiceRegistry}. Using this constructor creates a * registry that creates {@code OffHeapResourceIdentifier} entries as they are * referenced. */ private OffHeapIdentifierRegistry(int offHeapSize, MemoryUnit unit) { this.offHeapSize = unit.toBytes(offHeapSize); } /** * Instantiate a "closed" {@code ServiceRegistry}. Using this constructor creates a * registry that only returns {@code OffHeapResourceIdentifier} entries supplied * through the {@link #addResource} method. */ private OffHeapIdentifierRegistry() { this.offHeapSize = 0; } /** * Adds an off-heap resource of the given name to this registry. * * @param name the name of the resource * @param offHeapSize the off-heap size * @param unit the size unit type * @return {@code this} {@code OffHeapIdentifierRegistry} */ private OffHeapIdentifierRegistry addResource(String name, int offHeapSize, MemoryUnit unit) { this.pools.put(OffHeapResourceIdentifier.identifier(name), new TestOffHeapResource(unit.toBytes(offHeapSize))); return this; } private TestOffHeapResource getResource(String resourceName) { return this.pools.get(OffHeapResourceIdentifier.identifier(resourceName)); } private EhcacheStateServiceImpl getStoreManagerService() { return this.storeManagerService; } private IEntityMessenger getEntityMessenger() { return entityMessenger; } private ClientCommunicator getClientCommunicator() { return clientCommunicator; } private static Set<String> getIdentifiers(Set<OffHeapResourceIdentifier> pools) { Set<String> names = new HashSet<String>(); for (OffHeapResourceIdentifier identifier: pools) { names.add(identifier.getName()); } return Collections.unmodifiableSet(names); } @SuppressWarnings("unchecked") @Override public <T> T getService(ServiceConfiguration<T> serviceConfiguration) { if (serviceConfiguration.getServiceType().equals(ClientCommunicator.class)) { if (this.clientCommunicator == null) { this.clientCommunicator = mock(ClientCommunicator.class); } return (T) this.clientCommunicator; } else if (serviceConfiguration.getServiceType().equals(EhcacheStateService.class)) { EhcacheStateServiceConfig config = (EhcacheStateServiceConfig) serviceConfiguration; if (storeManagerService == null) { this.storeManagerService = new EhcacheStateServiceImpl(new OffHeapResources() { @Override public Set<OffHeapResourceIdentifier> getAllIdentifiers() { return pools.keySet(); } @Override public OffHeapResource getOffHeapResource(OffHeapResourceIdentifier identifier) { return pools.get(identifier); } }, config.getConfig().getConfiguration(), DEFAULT_MAPPER, service -> {}); } return (T) (this.storeManagerService); } else if (serviceConfiguration.getServiceType().equals(IEntityMessenger.class)) { if (this.entityMessenger == null) { this.entityMessenger = mock(IEntityMessenger.class); } return (T) this.entityMessenger; } else if(serviceConfiguration instanceof ConsumerManagementRegistryConfiguration) { return null; } else if(serviceConfiguration instanceof ActiveEntityMonitoringServiceConfiguration) { return null; } throw new UnsupportedOperationException("Registry.getService does not support " + serviceConfiguration.getClass().getName()); } } /** * Testing implementation of {@link OffHeapResource}. This is a "server-side" object. */ private static final class TestOffHeapResource implements OffHeapResource { private long capacity; private long used; private TestOffHeapResource(long capacity) { this.capacity = capacity; } @Override public boolean reserve(long size) throws IllegalArgumentException { if (size < 0) { throw new IllegalArgumentException(); } if (size > available()) { return false; } else { this.used += size; return true; } } @Override public void release(long size) throws IllegalArgumentException { if (size < 0) { throw new IllegalArgumentException(); } this.used -= size; } @Override public long available() { return this.capacity - this.used; } @Override public long capacity() { return capacity; } private long getUsed() { return used; } } private static class InvalidMessage extends EhcacheEntityMessage { @Override public void setId(long id) { throw new UnsupportedOperationException("TODO Implement me!"); } @Override public long getId() { throw new UnsupportedOperationException("TODO Implement me!"); } @Override public UUID getClientId() { throw new UnsupportedOperationException("TODO Implement me!"); } } }