/* * 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.spi.impl.operationservice.impl; import com.hazelcast.config.Config; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.spi.Operation; import com.hazelcast.spi.OperationService; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.TestHazelcastInstanceFactory; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import static com.hazelcast.spi.impl.operationservice.impl.Invocation.HeartbeatTimeout.NO_TIMEOUT__CALL_TIMEOUT_DISABLED; import static com.hazelcast.spi.impl.operationservice.impl.Invocation.HeartbeatTimeout.NO_TIMEOUT__CALL_TIMEOUT_NOT_EXPIRED; import static com.hazelcast.spi.impl.operationservice.impl.Invocation.HeartbeatTimeout.NO_TIMEOUT__HEARTBEAT_TIMEOUT_NOT_EXPIRED; import static com.hazelcast.spi.impl.operationservice.impl.Invocation.HeartbeatTimeout.NO_TIMEOUT__RESPONSE_AVAILABLE; import static com.hazelcast.spi.impl.operationservice.impl.Invocation.HeartbeatTimeout.TIMEOUT; import static com.hazelcast.spi.properties.GroupProperty.OPERATION_CALL_TIMEOUT_MILLIS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class Invocation_DetectHeartbeatTimeoutTest extends HazelcastTestSupport { @Test public void whenCallTimeoutDisabled() { Config config = new Config(); config.setProperty(OPERATION_CALL_TIMEOUT_MILLIS.getName(), "1000"); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance local = factory.newHazelcastInstance(); HazelcastInstance remote = factory.newHazelcastInstance(); OperationService opService = getOperationService(local); Operation operation = new VoidOperation(); InvocationFuture future = (InvocationFuture) opService.createInvocationBuilder( null, operation, getPartitionId(remote)) .setCallTimeout(Long.MAX_VALUE) .invoke(); Invocation invocation = future.invocation; assertEquals(Long.MAX_VALUE, invocation.op.getCallTimeout()); assertEquals(Long.MAX_VALUE, invocation.callTimeoutMillis); assertEquals(NO_TIMEOUT__CALL_TIMEOUT_DISABLED, invocation.detectTimeout(SECONDS.toMillis(1))); assertFalse(future.isDone()); } @Test public void whenResponseAvailable() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance local = factory.newHazelcastInstance(); HazelcastInstance remote = factory.newHazelcastInstance(); OperationService opService = getOperationService(local); Operation operation = new SlowOperation(SECONDS.toMillis(60)); InvocationFuture future = (InvocationFuture) opService.invokeOnPartition(null, operation, getPartitionId(remote)); Invocation invocation = future.invocation; invocation.pendingResponse = "foo"; invocation.backupsAcksExpected = 1; assertEquals(NO_TIMEOUT__RESPONSE_AVAILABLE, invocation.detectTimeout(SECONDS.toMillis(1))); assertFalse(future.isDone()); } @Test public void whenCallTimeoutNotExpired() { TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance local = factory.newHazelcastInstance(); HazelcastInstance remote = factory.newHazelcastInstance(); OperationService opService = getOperationService(local); Operation operation = new SlowOperation(SECONDS.toMillis(60)); InvocationFuture future = (InvocationFuture) opService.invokeOnPartition(null, operation, getPartitionId(remote)); Invocation invocation = future.invocation; assertEquals(NO_TIMEOUT__CALL_TIMEOUT_NOT_EXPIRED, invocation.detectTimeout(SECONDS.toMillis(1))); assertFalse(future.isDone()); } @Test public void whenCallTimeoutExpired_ButOperationHeartbeatHasNot() { Config config = new Config(); config.setProperty(OPERATION_CALL_TIMEOUT_MILLIS.getName(), "5000"); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance local = factory.newHazelcastInstance(config); HazelcastInstance remote = factory.newHazelcastInstance(config); OperationService opService = getOperationService(local); InvocationFuture future = (InvocationFuture) opService.invokeOnPartition(new SlowOperation(SECONDS.toMillis(60)) .setPartitionId(getPartitionId(remote))); assertDetectHeartbeatTimeoutEventually(future.invocation, NO_TIMEOUT__HEARTBEAT_TIMEOUT_NOT_EXPIRED); } /** * This test checks if the invocation expires eventually after the operation did manage to execute and did manage to send * some heartbeats but for whatever reason the response was not received. * * We do this by sending in a void operation that runs for an long period (so there are heartbeats) but on completion it * doesn't send a response. */ @Test public void whenExpiresEventually() { Config config = new Config(); config.setProperty(OPERATION_CALL_TIMEOUT_MILLIS.getName(), "5000"); TestHazelcastInstanceFactory factory = createHazelcastInstanceFactory(2); HazelcastInstance local = factory.newHazelcastInstance(config); HazelcastInstance remote = factory.newHazelcastInstance(config); OperationService opService = getOperationService(local); Operation operation = new VoidOperation(SECONDS.toMillis(20)); InvocationFuture future = (InvocationFuture) opService.invokeOnPartition(null, operation, getPartitionId(remote)); Invocation invocation = future.invocation; assertDetectHeartbeatTimeoutEventually(invocation, NO_TIMEOUT__CALL_TIMEOUT_NOT_EXPIRED); assertDetectHeartbeatTimeoutEventually(invocation, NO_TIMEOUT__HEARTBEAT_TIMEOUT_NOT_EXPIRED); assertDetectHeartbeatTimeoutEventually(invocation, TIMEOUT); } private void assertDetectHeartbeatTimeoutEventually(final Invocation invocation, final Invocation.HeartbeatTimeout yes) { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertEquals(yes, invocation.detectTimeout(SECONDS.toMillis(1))); } }); } }