/*
* Copyright 2014 NAVER Corp.
*
* 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.navercorp.pinpoint.rpc.stream;
import com.navercorp.pinpoint.rpc.*;
import com.navercorp.pinpoint.rpc.client.DefaultPinpointClientFactory;
import com.navercorp.pinpoint.rpc.client.PinpointClient;
import com.navercorp.pinpoint.rpc.client.PinpointClientFactory;
import com.navercorp.pinpoint.rpc.client.SimpleMessageListener;
import com.navercorp.pinpoint.rpc.packet.stream.StreamClosePacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCode;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreateFailPacket;
import com.navercorp.pinpoint.rpc.packet.stream.StreamCreatePacket;
import com.navercorp.pinpoint.rpc.server.PinpointServer;
import com.navercorp.pinpoint.rpc.server.PinpointServerAcceptor;
import com.navercorp.pinpoint.rpc.server.ServerMessageListener;
import com.navercorp.pinpoint.rpc.server.SimpleServerMessageListener;
import com.navercorp.pinpoint.rpc.util.PinpointRPCTestUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.util.SocketUtils;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class StreamChannelManagerTest {
private static int bindPort;
@BeforeClass
public static void setUp() throws IOException {
bindPort = SocketUtils.findAvailableTcpPort();
}
// Client to Server Stream
@Test
public void streamSuccessTest1() throws IOException, InterruptedException {
SimpleStreamBO bo = new SimpleStreamBO();
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo));
serverAcceptor.bind("localhost", bindPort);
PinpointClientFactory clientFactory = createSocketFactory();
try {
PinpointClient client = clientFactory.connect("127.0.0.1", bindPort);
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener);
int sendCount = 4;
for (int i = 0; i < sendCount; i++) {
sendRandomBytes(bo);
}
clientListener.getLatch().await();
Assert.assertEquals(sendCount, clientListener.getReceivedMessage().size());
clientContext.getStreamChannel().close();
PinpointRPCTestUtils.close(client);
} finally {
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
// Client to Server Stream
@Test
public void streamSuccessTest2() throws IOException, InterruptedException {
SimpleStreamBO bo = new SimpleStreamBO();
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo));
serverAcceptor.bind("localhost", bindPort);
PinpointClientFactory clientFactory = createSocketFactory();
try {
PinpointClient client = clientFactory.connect("127.0.0.1", bindPort);
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener);
RecordedStreamChannelMessageListener clientListener2 = new RecordedStreamChannelMessageListener(8);
ClientStreamChannelContext clientContext2 = client.openStream(new byte[0], clientListener2);
int sendCount = 4;
for (int i = 0; i < sendCount; i++) {
sendRandomBytes(bo);
}
clientListener.getLatch().await();
Assert.assertEquals(sendCount, clientListener.getReceivedMessage().size());
clientContext.getStreamChannel().close();
sendCount = 4;
for (int i = 0; i < sendCount; i++) {
sendRandomBytes(bo);
}
clientListener2.getLatch().await();
Assert.assertEquals(sendCount, clientListener.getReceivedMessage().size());
Assert.assertEquals(8, clientListener2.getReceivedMessage().size());
clientContext2.getStreamChannel().close();
PinpointRPCTestUtils.close(client);
} finally {
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
@Test
public void streamSuccessTest3() throws IOException, InterruptedException {
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null);
serverAcceptor.bind("localhost", bindPort);
SimpleStreamBO bo = new SimpleStreamBO();
PinpointClientFactory clientFactory = createSocketFactory(SimpleMessageListener.INSTANCE, new ServerListener(bo));
try {
PinpointClient client = clientFactory.connect("127.0.0.1", bindPort);
Thread.sleep(100);
List<PinpointSocket> writableServerList = serverAcceptor.getWritableSocketList();
Assert.assertEquals(1, writableServerList.size());
PinpointSocket writableServer = writableServerList.get(0);
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
if (writableServer instanceof PinpointServer) {
ClientStreamChannelContext clientContext = ((PinpointServer)writableServer).openStream(new byte[0], clientListener);
int sendCount = 4;
for (int i = 0; i < sendCount; i++) {
sendRandomBytes(bo);
}
clientListener.getLatch().await();
Assert.assertEquals(sendCount, clientListener.getReceivedMessage().size());
clientContext.getStreamChannel().close();
} else {
Assert.fail();
}
PinpointRPCTestUtils.close(client);
} finally {
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
@Test
public void streamClosedTest1() throws IOException, InterruptedException {
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null);
serverAcceptor.bind("localhost", bindPort);
PinpointClientFactory clientFactory = createSocketFactory();
try {
PinpointClient client = clientFactory.connect("127.0.0.1", bindPort);
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener);
StreamCreateFailPacket createFailPacket = clientContext.getCreateFailPacket();
if (createFailPacket == null) {
Assert.fail();
}
clientContext.getStreamChannel().close();
PinpointRPCTestUtils.close(client);
} finally {
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
@Test
public void streamClosedTest2() throws IOException, InterruptedException {
SimpleStreamBO bo = new SimpleStreamBO();
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, new ServerListener(bo));
serverAcceptor.bind("localhost", bindPort);
PinpointClientFactory clientFactory = createSocketFactory();
PinpointClient client = null;
try {
client = clientFactory.connect("127.0.0.1", bindPort);
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
ClientStreamChannelContext clientContext = client.openStream(new byte[0], clientListener);
Assert.assertEquals(1, bo.getStreamChannelContextSize());
clientContext.getStreamChannel().close();
Thread.sleep(100);
Assert.assertEquals(0, bo.getStreamChannelContextSize());
} finally {
PinpointRPCTestUtils.close(client);
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
// ServerSocket to Client Stream
// ServerStreamChannel first close.
@Test(expected = PinpointSocketException.class)
public void streamClosedTest3() throws IOException, InterruptedException {
PinpointServerAcceptor serverAcceptor = createServerFactory(SimpleServerMessageListener.DUPLEX_ECHO_INSTANCE, null);
serverAcceptor.bind("localhost", bindPort);
SimpleStreamBO bo = new SimpleStreamBO();
PinpointClientFactory clientFactory = createSocketFactory(SimpleMessageListener.INSTANCE, new ServerListener(bo));
PinpointClient client = clientFactory.connect("127.0.0.1", bindPort);
try {
Thread.sleep(100);
List<PinpointSocket> writableServerList = serverAcceptor.getWritableSocketList();
Assert.assertEquals(1, writableServerList.size());
PinpointSocket writableServer = writableServerList.get(0);
if (writableServer instanceof PinpointServer) {
RecordedStreamChannelMessageListener clientListener = new RecordedStreamChannelMessageListener(4);
ClientStreamChannelContext clientContext = ((PinpointServer)writableServer).openStream(new byte[0], clientListener);
StreamChannelContext streamChannelContext = client.findStreamChannel(2);
streamChannelContext.getStreamChannel().close();
sendRandomBytes(bo);
Thread.sleep(100);
clientContext.getStreamChannel().close();
} else {
Assert.fail();
}
} finally {
PinpointRPCTestUtils.close(client);
clientFactory.release();
PinpointRPCTestUtils.close(serverAcceptor);
}
}
private PinpointServerAcceptor createServerFactory(ServerMessageListener severMessageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener) {
PinpointServerAcceptor serverAcceptor = new PinpointServerAcceptor();
if (severMessageListener != null) {
serverAcceptor.setMessageListener(severMessageListener);
}
if (serverStreamChannelMessageListener != null) {
serverAcceptor.setServerStreamChannelMessageListener(serverStreamChannelMessageListener);
}
return serverAcceptor;
}
private PinpointClientFactory createSocketFactory() {
PinpointClientFactory clientFactory = new DefaultPinpointClientFactory();
return clientFactory;
}
private PinpointClientFactory createSocketFactory(MessageListener messageListener, ServerStreamChannelMessageListener serverStreamChannelMessageListener) {
PinpointClientFactory clientFactory = new DefaultPinpointClientFactory();
clientFactory.setMessageListener(messageListener);
clientFactory.setServerStreamChannelMessageListener(serverStreamChannelMessageListener);
return clientFactory;
}
private void sendRandomBytes(SimpleStreamBO bo) {
byte[] openBytes = TestByteUtils.createRandomByte(30);
bo.sendResponse(openBytes);
}
class ServerListener implements ServerStreamChannelMessageListener {
private final SimpleStreamBO bo;
public ServerListener(SimpleStreamBO bo) {
this.bo = bo;
}
@Override
public StreamCode handleStreamCreate(ServerStreamChannelContext streamChannelContext, StreamCreatePacket packet) {
bo.addServerStreamChannelContext(streamChannelContext);
return StreamCode.OK;
}
@Override
public void handleStreamClose(ServerStreamChannelContext streamChannelContext, StreamClosePacket packet) {
bo.removeServerStreamChannelContext(streamChannelContext);
}
}
class SimpleStreamBO {
private final List<ServerStreamChannelContext> serverStreamChannelContextList;
public SimpleStreamBO() {
serverStreamChannelContextList = new CopyOnWriteArrayList<ServerStreamChannelContext>();
}
public void addServerStreamChannelContext(ServerStreamChannelContext context) {
serverStreamChannelContextList.add(context);
}
public void removeServerStreamChannelContext(ServerStreamChannelContext context) {
serverStreamChannelContextList.remove(context);
}
void sendResponse(byte[] data) {
for (ServerStreamChannelContext context : serverStreamChannelContextList) {
context.getStreamChannel().sendData(data);
}
}
int getStreamChannelContextSize() {
return serverStreamChannelContextList.size();
}
}
}