/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * 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 com.hazelcast.instance; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.OutOfMemoryHandler; import com.hazelcast.memory.MemoryUnit; import com.hazelcast.test.HazelcastSerialClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.QuickTest; import com.hazelcast.util.MemoryInfoAccessor; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.mockito.verification.VerificationMode; import static org.junit.Assert.assertArrayEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(HazelcastSerialClassRunner.class) @Category(QuickTest.class) public class OutOfMemoryErrorDispatcherTest extends HazelcastTestSupport { @Before public void before() { OutOfMemoryErrorDispatcher.clearServers(); } @Test public void onOutOfMemory() { OutOfMemoryError oome = new OutOfMemoryError(); OutOfMemoryHandler handler = mock(OutOfMemoryHandler.class); when(handler.shouldHandle(oome)).thenReturn(Boolean.TRUE); HazelcastInstance hz1 = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz1); OutOfMemoryErrorDispatcher.setServerHandler(handler); HazelcastInstance[] registeredInstances = OutOfMemoryErrorDispatcher.current(); OutOfMemoryErrorDispatcher.onOutOfMemory(oome); //make sure the handler is called verify(handler).onOutOfMemory(oome, registeredInstances); //make sure that the registered instances are removed. assertArrayEquals(new HazelcastInstance[]{}, OutOfMemoryErrorDispatcher.current()); } @Test public void register() { HazelcastInstance hz1 = mock(HazelcastInstance.class); HazelcastInstance hz2 = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz1); assertArrayEquals(new HazelcastInstance[]{hz1}, OutOfMemoryErrorDispatcher.current()); OutOfMemoryErrorDispatcher.registerServer(hz2); assertArrayEquals(new HazelcastInstance[]{hz1, hz2}, OutOfMemoryErrorDispatcher.current()); } @Test(expected = IllegalArgumentException.class) public void register_whenNull() { OutOfMemoryErrorDispatcher.registerServer(null); } @Test public void deregister_Existing() { HazelcastInstance hz1 = mock(HazelcastInstance.class); HazelcastInstance hz2 = mock(HazelcastInstance.class); HazelcastInstance hz3 = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz1); OutOfMemoryErrorDispatcher.registerServer(hz2); OutOfMemoryErrorDispatcher.registerServer(hz3); OutOfMemoryErrorDispatcher.deregisterServer(hz2); assertArrayEquals(new HazelcastInstance[]{hz1, hz3}, OutOfMemoryErrorDispatcher.current()); OutOfMemoryErrorDispatcher.deregisterServer(hz1); assertArrayEquals(new HazelcastInstance[]{hz3}, OutOfMemoryErrorDispatcher.current()); OutOfMemoryErrorDispatcher.deregisterServer(hz3); assertArrayEquals(new HazelcastInstance[]{}, OutOfMemoryErrorDispatcher.current()); } @Test public void deregister_nonExisting() { HazelcastInstance instance = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.deregisterServer(instance); } @Test(expected = IllegalArgumentException.class) public void deregister_null() { OutOfMemoryErrorDispatcher.deregisterServer(null); } @Test public void test_OutOfMemoryHandler_shouldHandle_true() { test_OutOfMemoryHandler_with_shouldHandle(Boolean.TRUE, times(1)); } @Test public void test_OutOfMemoryHandler_shouldHandle_false() { test_OutOfMemoryHandler_with_shouldHandle(Boolean.FALSE, never()); } private void test_OutOfMemoryHandler_with_shouldHandle(Boolean answer, VerificationMode verificationMode) { OutOfMemoryError oome = new OutOfMemoryError(); HazelcastInstance hz = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz); OutOfMemoryHandler handler = mock(OutOfMemoryHandler.class); when(handler.shouldHandle(oome)).thenReturn(answer); OutOfMemoryErrorDispatcher.setServerHandler(handler); OutOfMemoryErrorDispatcher.onOutOfMemory(oome); verify(handler, verificationMode).onOutOfMemory(oome, new HazelcastInstance[]{hz}); } @Test public void test_DefaultOutOfMemoryHandler_whenGcOverheadLimitExceeded() { OutOfMemoryError oome = new OutOfMemoryError(DefaultOutOfMemoryHandler.GC_OVERHEAD_LIMIT_EXCEEDED); HazelcastInstance hz = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz); OutOfMemoryHandler handler = spy(new DefaultOutOfMemoryHandler()); when(handler.shouldHandle(oome)).thenCallRealMethod(); OutOfMemoryErrorDispatcher.setServerHandler(handler); OutOfMemoryErrorDispatcher.onOutOfMemory(oome); verify(handler).onOutOfMemory(oome, new HazelcastInstance[]{hz}); } @Test public void test_DefaultOutOfMemoryHandler_total_smallerThan_max() { test_DefaultOutOfMemoryHandler_using_accessor(new MemoryInfoAccessor() { @Override public long getMaxMemory() { return MemoryUnit.MEGABYTES.toBytes(100); } @Override public long getTotalMemory() { return MemoryUnit.MEGABYTES.toBytes(80); } @Override public long getFreeMemory() { return MemoryUnit.MEGABYTES.toBytes(10); } }, never()); } @Test public void test_DefaultOutOfMemoryHandler_total_equalTo_max() { test_DefaultOutOfMemoryHandler_using_accessor(new MemoryInfoAccessor() { @Override public long getMaxMemory() { return MemoryUnit.MEGABYTES.toBytes(100); } @Override public long getTotalMemory() { return MemoryUnit.MEGABYTES.toBytes(100); } @Override public long getFreeMemory() { return MemoryUnit.MEGABYTES.toBytes(20); } }, never()); } @Test public void test_DefaultOutOfMemoryHandler_not_enough_memory() { test_DefaultOutOfMemoryHandler_using_accessor(new MemoryInfoAccessor() { @Override public long getMaxMemory() { return MemoryUnit.MEGABYTES.toBytes(100); } @Override public long getTotalMemory() { return MemoryUnit.MEGABYTES.toBytes(100); } @Override public long getFreeMemory() { return MemoryUnit.MEGABYTES.toBytes(5); } }, times(1)); } private void test_DefaultOutOfMemoryHandler_using_accessor(MemoryInfoAccessor memoryInfoAccessor, VerificationMode verificationMode) { OutOfMemoryError oome = new OutOfMemoryError(); HazelcastInstance hz = mock(HazelcastInstance.class); OutOfMemoryErrorDispatcher.registerServer(hz); OutOfMemoryHandler handler = spy(new DefaultOutOfMemoryHandler(0.1d, memoryInfoAccessor)); OutOfMemoryErrorDispatcher.setServerHandler(handler); OutOfMemoryErrorDispatcher.onOutOfMemory(oome); verify(handler, verificationMode).onOutOfMemory(oome, new HazelcastInstance[]{hz}); } }