|
17 | 17 | package com.alipay.sofa.jraft.core; |
18 | 18 |
|
19 | 19 | import java.io.File; |
| 20 | +import java.lang.reflect.Constructor; |
20 | 21 | import java.nio.ByteBuffer; |
21 | 22 | import java.util.ArrayList; |
22 | 23 | import java.util.Arrays; |
|
72 | 73 | import com.alipay.sofa.jraft.option.BootstrapOptions; |
73 | 74 | import com.alipay.sofa.jraft.option.NodeOptions; |
74 | 75 | import com.alipay.sofa.jraft.option.RaftOptions; |
| 76 | +import com.alipay.sofa.jraft.rpc.RpcRequests.AppendEntriesResponse; |
| 77 | +import com.alipay.sofa.jraft.rpc.RpcRequests.ReadIndexResponse; |
| 78 | +import com.alipay.sofa.jraft.rpc.RpcResponseClosure; |
| 79 | +import com.alipay.sofa.jraft.rpc.RpcResponseClosureAdapter; |
75 | 80 | import com.alipay.sofa.jraft.rpc.RaftRpcServerFactory; |
76 | 81 | import com.alipay.sofa.jraft.rpc.RpcServer; |
77 | 82 | import com.alipay.sofa.jraft.storage.SnapshotThrottle; |
@@ -1454,6 +1459,61 @@ public void run(final Status status, final long index, final byte[] reqCtx) { |
1454 | 1459 | cluster.stopAll(); |
1455 | 1460 | } |
1456 | 1461 |
|
| 1462 | + @Test |
| 1463 | + public void testReadIndexHeartbeatResponseClosureFailsWhenFilteredRecipientsCannotReachQuorum() throws Exception { |
| 1464 | + final NodeImpl node = new NodeImpl(); |
| 1465 | + try { |
| 1466 | + final Status[] callbackStatus = new Status[1]; |
| 1467 | + final ReadIndexResponse[] callbackResponse = new ReadIndexResponse[1]; |
| 1468 | + final RpcResponseClosure<ReadIndexResponse> done = new RpcResponseClosureAdapter<ReadIndexResponse>() { |
| 1469 | + |
| 1470 | + @Override |
| 1471 | + public void run(final Status status) { |
| 1472 | + callbackStatus[0] = status; |
| 1473 | + callbackResponse[0] = getResponse(); |
| 1474 | + } |
| 1475 | + }; |
| 1476 | + |
| 1477 | + final RpcResponseClosureAdapter<AppendEntriesResponse> heartbeatDone = newReadIndexHeartbeatResponseClosure( |
| 1478 | + node, done, ReadIndexResponse.newBuilder().setIndex(11), 3, 2); |
| 1479 | + |
| 1480 | + heartbeatDone.setResponse(AppendEntriesResponse.newBuilder().setTerm(1).setSuccess(true).build()); |
| 1481 | + heartbeatDone.run(Status.OK()); |
| 1482 | + assertNull(callbackStatus[0]); |
| 1483 | + assertNull(callbackResponse[0]); |
| 1484 | + |
| 1485 | + heartbeatDone.setResponse(AppendEntriesResponse.newBuilder().setTerm(1).setSuccess(false).build()); |
| 1486 | + heartbeatDone.run(Status.OK()); |
| 1487 | + assertNotNull(callbackStatus[0]); |
| 1488 | + assertTrue(callbackStatus[0].isOk()); |
| 1489 | + assertNotNull(callbackResponse[0]); |
| 1490 | + assertFalse(callbackResponse[0].getSuccess()); |
| 1491 | + assertEquals(11, callbackResponse[0].getIndex()); |
| 1492 | + } finally { |
| 1493 | + assertEquals(0, NodeImpl.GLOBAL_NUM_NODES.decrementAndGet()); |
| 1494 | + } |
| 1495 | + } |
| 1496 | + |
| 1497 | + @SuppressWarnings("unchecked") |
| 1498 | + private RpcResponseClosureAdapter<AppendEntriesResponse> newReadIndexHeartbeatResponseClosure(final NodeImpl node, |
| 1499 | + final RpcResponseClosure<ReadIndexResponse> done, |
| 1500 | + final ReadIndexResponse.Builder respBuilder, |
| 1501 | + final int quorum, |
| 1502 | + final int expectedFollowerResponses) |
| 1503 | + throws Exception { |
| 1504 | + for (final Class<?> innerClass : NodeImpl.class.getDeclaredClasses()) { |
| 1505 | + if ("ReadIndexHeartbeatResponseClosure".equals(innerClass.getSimpleName())) { |
| 1506 | + final Constructor<?> constructor = innerClass.getDeclaredConstructor(NodeImpl.class, |
| 1507 | + RpcResponseClosure.class, ReadIndexResponse.Builder.class, int.class, int.class); |
| 1508 | + constructor.setAccessible(true); |
| 1509 | + return (RpcResponseClosureAdapter<AppendEntriesResponse>) constructor.newInstance(node, done, |
| 1510 | + respBuilder, quorum, expectedFollowerResponses); |
| 1511 | + } |
| 1512 | + } |
| 1513 | + fail("ReadIndexHeartbeatResponseClosure not found"); |
| 1514 | + return null; |
| 1515 | + } |
| 1516 | + |
1457 | 1517 | @Test |
1458 | 1518 | public void testReadIndexTimeout() throws Exception { |
1459 | 1519 | final List<PeerId> peers = TestUtils.generatePeers(3); |
|
0 commit comments