/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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 io.datakernel.rpc.protocol.stream;
import com.google.common.collect.Lists;
import com.google.common.net.InetAddresses;
import io.datakernel.async.CompletionCallback;
import io.datakernel.async.IgnoreCompletionCallback;
import io.datakernel.async.ResultCallback;
import io.datakernel.bytebuf.ByteBufPool;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.rpc.client.RpcClient;
import io.datakernel.rpc.protocol.RpcMessage;
import io.datakernel.rpc.server.RpcRequestHandler;
import io.datakernel.rpc.server.RpcServer;
import io.datakernel.serializer.BufferSerializer;
import io.datakernel.serializer.SerializerBuilder;
import io.datakernel.stream.StreamConsumers;
import io.datakernel.stream.StreamProducer;
import io.datakernel.stream.StreamProducers;
import io.datakernel.stream.processor.StreamBinaryDeserializer;
import io.datakernel.stream.processor.StreamBinarySerializer;
import io.datakernel.stream.processor.StreamLZ4Compressor;
import io.datakernel.stream.processor.StreamLZ4Decompressor;
import org.junit.Before;
import org.junit.Test;
import java.net.InetSocketAddress;
import java.util.List;
import static io.datakernel.bytebuf.ByteBufPool.getPoolItemsString;
import static io.datakernel.eventloop.FatalErrorHandlers.rethrowOnAnyError;
import static io.datakernel.rpc.client.sender.RpcStrategies.server;
import static java.lang.ClassLoader.getSystemClassLoader;
import static org.junit.Assert.assertEquals;
public class RpcBinaryProtocolTest {
private static final int LISTEN_PORT = 12345;
private static final InetSocketAddress address = new InetSocketAddress(InetAddresses.forString("127.0.0.1"), LISTEN_PORT);
interface TestService {
void call(String request, ResultCallback<String> resultCallback);
}
@Before
public void before() {
ByteBufPool.clear();
ByteBufPool.setSizes(0, Integer.MAX_VALUE);
}
@Test
public void test() throws Exception {
final String testMessage = "Test";
final Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
final RpcClient client = RpcClient.create(eventloop)
.withMessageTypes(String.class)
.withStrategy(server(address));
final RpcServer server = RpcServer.create(eventloop)
.withMessageTypes(String.class)
.withHandler(String.class, String.class, new RpcRequestHandler<String, String>() {
@Override
public void run(String request, ResultCallback<String> callback) {
callback.setResult("Hello, " + request + "!");
}
})
.withListenAddress(address);
server.listen();
final int countRequests = 10;
final List<String> results = Lists.newArrayList();
class ResultObserver extends ResultCallback<String> {
@Override
public void onException(Exception exception) {
client.stop(new CompletionCallback() {
@Override
public void onComplete() {
System.out.println("Client stopped");
server.close(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception exception) {
throw new RuntimeException(exception);
}
});
}
@Override
public void onResult(String result) {
results.add(result);
if (results.size() == countRequests) {
client.stop(new CompletionCallback() {
@Override
public void onComplete() {
System.out.println("Client stopped");
server.close(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception exception) {
throw new RuntimeException(exception);
}
});
}
}
}
;
client.start(new CompletionCallback() {
@Override
public void onComplete() {
for (int i = 0; i < countRequests; i++) {
client.sendRequest(testMessage, 1000, new ResultObserver());
}
}
@Override
public void onException(Exception e) {
new ResultObserver().setException(e);
}
});
eventloop.run();
assertEquals(countRequests, results.size());
for (int i = 0; i < countRequests; i++) {
assertEquals("Hello, " + testMessage + "!", results.get(i));
}
assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
}
@Test
public void testCompression() {
BufferSerializer<RpcMessage> serializer = SerializerBuilder.create(getSystemClassLoader())
.withSubclasses(RpcMessage.MESSAGE_TYPES, String.class)
.build(RpcMessage.class);
int countRequests = 10;
Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
int defaultPacketSize = 1 << 10;
int maxPacketSize = 1 << 16;
// client side
String testMessage = "Test";
List<RpcMessage> sourceList = Lists.newArrayList();
for (int i = 0; i < countRequests; i++) {
sourceList.add(RpcMessage.of(i, testMessage));
}
StreamProducer<RpcMessage> client = StreamProducers.ofIterable(eventloop, sourceList);
StreamLZ4Compressor compressorClient = StreamLZ4Compressor.fastCompressor(eventloop);
StreamLZ4Decompressor decompressorClient = StreamLZ4Decompressor.create(eventloop);
StreamBinarySerializer<RpcMessage> serializerClient = StreamBinarySerializer.create(eventloop, serializer)
.withDefaultBufferSize(defaultPacketSize)
.withMaxMessageSize(maxPacketSize);
StreamBinaryDeserializer<RpcMessage> deserializerClient = StreamBinaryDeserializer.create(eventloop, serializer)
.withMaxMessageSize(maxPacketSize);
// server side
StreamLZ4Compressor compressorServer = StreamLZ4Compressor.fastCompressor(eventloop);
StreamLZ4Decompressor decompressorServer = StreamLZ4Decompressor.create(eventloop);
StreamBinarySerializer<RpcMessage> serializerServer = StreamBinarySerializer.create(eventloop, serializer)
.withDefaultBufferSize(defaultPacketSize)
.withMaxMessageSize(maxPacketSize);
StreamBinaryDeserializer<RpcMessage> deserializerServer = StreamBinaryDeserializer.create(eventloop, serializer)
.withMaxMessageSize(maxPacketSize);
StreamConsumers.ToList<RpcMessage> results = new StreamConsumers.ToList<>(eventloop);
client.streamTo(serializerClient.getInput());
serializerClient.getOutput().streamTo(compressorClient.getInput());
compressorClient.getOutput().streamTo(decompressorServer.getInput());
decompressorServer.getOutput().streamTo(deserializerServer.getInput());
deserializerServer.getOutput().streamTo(serializerServer.getInput());
serializerServer.getOutput().streamTo(compressorServer.getInput());
compressorServer.getOutput().streamTo(decompressorClient.getInput());
decompressorClient.getOutput().streamTo(deserializerClient.getInput());
deserializerClient.getOutput().streamTo(results);
eventloop.run();
List<RpcMessage> resultsData = results.getList();
assertEquals(countRequests, resultsData.size());
for (int i = 0; i < countRequests; i++) {
assertEquals(i, resultsData.get(i).getCookie());
String data = (String) resultsData.get(i).getData();
assertEquals(testMessage, data);
}
assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
}
}