package com.hazelcast.spi.impl.operationservice.impl;
import com.hazelcast.instance.Node;
import com.hazelcast.internal.serialization.InternalSerializationService;
import com.hazelcast.internal.serialization.impl.DefaultSerializationServiceBuilder;
import com.hazelcast.internal.serialization.impl.HeapData;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.nio.Address;
import com.hazelcast.nio.ConnectionManager;
import com.hazelcast.nio.Packet;
import com.hazelcast.nio.serialization.Portable;
import com.hazelcast.nio.serialization.PortableReader;
import com.hazelcast.nio.serialization.PortableWriter;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.impl.operationservice.impl.responses.BackupAckResponse;
import com.hazelcast.spi.impl.operationservice.impl.responses.CallTimeoutResponse;
import com.hazelcast.spi.impl.operationservice.impl.responses.ErrorResponse;
import com.hazelcast.spi.impl.operationservice.impl.responses.NormalResponse;
import com.hazelcast.test.HazelcastParallelClassRunner;
import com.hazelcast.test.annotation.ParallelTest;
import com.hazelcast.test.annotation.QuickTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import java.io.IOException;
import static com.hazelcast.spi.OperationAccessor.setCallId;
import static com.hazelcast.spi.OperationAccessor.setCallerAddress;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(HazelcastParallelClassRunner.class)
@Category({QuickTest.class, ParallelTest.class})
public class OutboundResponseHandlerTest {
private OutboundResponseHandler handler;
private Address thisAddress;
private InternalSerializationService serializationService;
private ILogger logger = Logger.getLogger(OutboundResponseHandlerTest.class);
private Node node;
private Address thatAddress;
private ConnectionManager connectionManager;
@Before
public void setup() throws Exception {
thisAddress = new Address("127.0.0.1", 5701);
thatAddress = new Address("127.0.0.1", 5702);
serializationService = new DefaultSerializationServiceBuilder().build();
node = mock(Node.class);
connectionManager = mock(ConnectionManager.class);
when(node.getConnectionManager()).thenReturn(connectionManager);
handler = new OutboundResponseHandler(thisAddress, serializationService, node, logger);
}
@Test
public void sendResponse_whenNormalResponse() {
NormalResponse response = new NormalResponse("foo", 10, 1, false);
Operation op = new DummyOperation();
setCallId(op, response.getCallId());
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, response);
// verify that the right object was send
assertEquals(serializationService.toData(response), argument.getValue());
}
@Test
public void sendResponse_whenPortable() {
Object response = new PortableAddress("Sesame Street",1);
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, response);
// verify that the right object was send
NormalResponse expected = new NormalResponse(response, op.getCallId(), 0, op.isUrgent());
assertEquals(serializationService.toData(expected), argument.getValue());
}
@Test
public void sendResponse_whenOrdinaryValue() {
Object response = "foobar";
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, response);
// verify that the right object was send
NormalResponse expected = new NormalResponse(response, op.getCallId(), 0, op.isUrgent());
assertEquals(serializationService.toData(expected), argument.getValue());
}
@Test
public void sendResponse_whenNull() {
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, null);
// verify that the right object was send
NormalResponse expected = new NormalResponse(null, op.getCallId(), 0, op.isUrgent());
assertEquals(serializationService.toData(expected), argument.getValue());
}
@Test
public void sendResponse_whenTimeoutResponse() {
CallTimeoutResponse response = new CallTimeoutResponse(10, false);
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, response);
// verify that the right object was send
assertEquals(serializationService.toData(response), argument.getValue());
}
@Test
public void sendResponse_whenErrorResponse() {
ErrorResponse response = new ErrorResponse(new Exception(), 10, false);
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, response);
// verify that the right object was send
assertEquals(serializationService.toData(response), argument.getValue());
}
@Test
public void sendResponse_whenThrowable() {
Exception exception = new Exception();
Operation op = new DummyOperation();
setCallId(op, 10);
setCallerAddress(op, thatAddress);
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
when(connectionManager.transmit(argument.capture(), eq(thatAddress))).thenReturn(true);
// make the call
handler.sendResponse(op, exception);
// verify that the right object was send
ErrorResponse expectedResponse = new ErrorResponse(exception, op.getCallId(), op.isUrgent());
assertEquals(serializationService.toData(expectedResponse), argument.getValue());
}
@Test
public void toBackupAckPacket() {
testToBackupAckPacket(1, false);
testToBackupAckPacket(2, true);
}
private void testToBackupAckPacket(int callId, boolean urgent) {
Packet packet = handler.toBackupAckPacket(callId, urgent);
HeapData expected = serializationService.toData(new BackupAckResponse(callId, urgent));
assertEquals(expected, new HeapData(packet.toByteArray()));
}
@Test
public void toNormalResponsePacket_whenNormalValues() {
testToNormalResponsePacket("foo", 1, 0, false);
testToNormalResponsePacket("foo", 2, 0, true);
testToNormalResponsePacket("foo", 3, 2, false);
}
@Test
public void toNormalResponsePacket_whenNullValue() {
testToNormalResponsePacket(null, 1, 2, false);
}
@Test
public void toNormalResponsePacket_whenDataValue() {
testToNormalResponsePacket(serializationService.toBytes("foobar"), 1, 2, false);
}
private void testToNormalResponsePacket(Object value, int callId, int backupAcks, boolean urgent) {
Packet packet = handler.toNormalResponsePacket(callId, backupAcks, urgent, value);
HeapData expected = serializationService.toData(new NormalResponse(value, callId, backupAcks, urgent));
assertEquals(expected, new HeapData(packet.toByteArray()));
}
static class PortableAddress implements Portable {
private String street;
private int no;
public PortableAddress() {
}
public PortableAddress(String street, int no) {
this.street = street;
this.no = no;
}
@Override
public int getClassId() {
return 2;
}
@Override
public void writePortable(PortableWriter writer) throws IOException {
writer.writeInt("no", no);
writer.writeUTF("street", street);
}
@Override
public void readPortable(PortableReader reader) throws IOException {
street = reader.readUTF("street");
no = reader.readInt("no");
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
PortableAddress that = (PortableAddress) o;
if (no != that.no) {
return false;
}
if (street != null ? !street.equals(that.street) : that.street != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = street != null ? street.hashCode() : 0;
result = 31 * result + no;
return result;
}
@Override
public int getFactoryId() {
return 1;
}
}
}