package biz.paluch.logging.gelf.intern.sender;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import biz.paluch.logging.gelf.intern.ErrorReporter;
import biz.paluch.logging.gelf.intern.GelfMessage;
/**
* @author <a href="mailto:mpaluch@paluch.biz">Mark Paluch</a>
*/
public class GelfTCPSenderIntegrationTests {
public static final int PORT = 1234;
private ByteArrayOutputStream out = new ByteArrayOutputStream();
private final CountDownLatch latch = new CountDownLatch(1);
private final Queue<Socket> sockets = new LinkedBlockingQueue<Socket>();
private volatile ServerSocket serverSocket;
private volatile boolean loopActive = true;
private Thread thread;
@BeforeEach
void setUp() throws Exception {
serverSocket = new ServerSocket(PORT);
serverSocket.setSoTimeout(10000);
thread = new Thread("GelfTCPSenderIntegrationTest-server") {
@Override
public void run() {
while (loopActive) {
try {
Thread.sleep(0);
if (serverSocket.isClosed()) {
continue;
}
Socket socket = serverSocket.accept();
sockets.add(socket);
socket.setKeepAlive(true);
InputStream inputStream = socket.getInputStream();
while (!socket.isClosed()) {
IOUtils.copy(inputStream, out);
Thread.sleep(1);
if (latch.getCount() == 0) {
socket.close();
}
}
} catch (IOException e) {
} catch (InterruptedException e) {
return;
}
}
}
};
}
@AfterEach
void tearDown() throws IOException {
thread.interrupt();
if (!serverSocket.isClosed()) {
serverSocket.close();
}
}
@Test
public void simpleTransport() throws Exception {
thread.start();
SmallBufferTCPSender sender = new SmallBufferTCPSender("localhost", PORT, 1000, 1000, new ErrorReporter() {
@Override
public void reportError(String message, Exception e) {
}
});
GelfMessage gelfMessage = new GelfMessage("hello", StringUtils.repeat("hello", 100000), PORT, "7");
ByteBuffer byteBuffer = gelfMessage.toTCPBuffer();
int size = byteBuffer.remaining();
sender.sendMessage(gelfMessage);
sender.close();
loopActive = false;
latch.countDown();
thread.join();
assertThat(out.size()).isEqualTo(size);
}
@Test
public void shouldRecoverFromBrokenPipe() throws Exception {
thread.start();
SmallBufferTCPSender sender = new SmallBufferTCPSender("localhost", PORT, 1000, 1000, new ErrorReporter() {
@Override
public void reportError(String message, Exception e) {
}
});
GelfMessage gelfMessage = new GelfMessage("hello", StringUtils.repeat("hello", 100000), PORT, "7");
ByteBuffer byteBuffer = gelfMessage.toTCPBuffer();
assertThat(sender.sendMessage(gelfMessage)).isTrue();
sockets.poll().close();
assertThat(sender.sendMessage(gelfMessage)).isTrue();
sender.close();
}
@Test
public void shouldRecoverFromClosedPort() throws Exception {
thread.start();
SmallBufferTCPSender sender = new SmallBufferTCPSender("localhost", PORT, 1000, 1000, new ErrorReporter() {
@Override
public void reportError(String message, Exception e) {
}
});
GelfMessage gelfMessage = new GelfMessage("hello", StringUtils.repeat("hello", 100000), PORT, "7");
ByteBuffer byteBuffer = gelfMessage.toTCPBuffer();
assertThat(sender.sendMessage(gelfMessage)).isTrue();
sockets.poll().close();
serverSocket.close();
assertThat(sender.sendMessage(gelfMessage)).isFalse();
serverSocket = new ServerSocket(PORT);
assertThat(sender.sendMessage(gelfMessage)).isTrue();
sender.close();
}
static class SmallBufferTCPSender extends GelfTCPSender {
public SmallBufferTCPSender(String host, int port, int connectTimeoutMs, int readTimeoutMs, ErrorReporter errorReporter)
throws IOException {
super(host, port, connectTimeoutMs, readTimeoutMs, errorReporter);
}
@Override
protected SocketChannel createSocketChannel(int readTimeoutMs, boolean keepAlive) throws IOException {
SocketChannel socketChannel = super.createSocketChannel(readTimeoutMs, keepAlive);
socketChannel.socket().setSendBufferSize(100);
return socketChannel;
}
}
}