package netflix.karyon.jersey.blocking;
import static org.junit.Assert.assertEquals;
import io.netty.util.ResourceLeakDetector;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Filter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import netflix.karyon.Karyon;
import netflix.karyon.KaryonServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.netflix.governator.guice.BootstrapModule;
public class JerseyBlockingTest {
private static KaryonServer server;
static ByteArrayOutputStream buffer;
@BeforeClass
public static void setUpBefore() throws Exception {
server = Karyon.forApplication( JerseyBlockingModule.class, (BootstrapModule[])null );
server.start();
}
@AfterClass
public static void cleanUpAfter() throws Exception {
server.shutdown();
}
private static int postData( String path, String payload ) throws IOException {
URL url = new URL( path );
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type","application/json");
con.setDoOutput(true);
con.setDoInput(true);
con.setConnectTimeout( 10000 );
con.setReadTimeout( 20000 );
con.getOutputStream().write( payload.getBytes("UTF-8") );
con.getOutputStream().flush();
con.getOutputStream().close();
int status = con.getResponseCode();
if( status != 200 ) {
return status;
}
//read the response
byte[] buffer = new byte[ 1024 ];
while( con.getInputStream().read( buffer ) > 0 ) {
;
}
return 200;
}
private String makePayload( int size ) {
StringBuilder buffer = new StringBuilder();
buffer.append("{\"key\":\"");
for( int i = 0; i < size; ++i ) {
buffer.append(( Byte.toString( (byte)( i & 0xFF ) ) ) );
}
return buffer.append("\"}").toString();
}
@Test
public void runJerseyTest() throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
final Random rnd = new Random();
final AtomicInteger errors = new AtomicInteger();
//let Netty blow in our face
ResourceLeakDetector.setLevel( ResourceLeakDetector.Level.PARANOID );
//tap to the logger, so we can catch leak error
Logger.getLogger( "io.netty.util.ResourceLeakDetector" ).setFilter( new Filter() {
@Override
public boolean isLoggable(LogRecord record) {
if( record.getLevel() == Level.SEVERE && record.getMessage().contains("LEAK") ) {
errors.incrementAndGet();
}
return true;
}
});
for( int i = 0; i < 200; ++i ) {
service.execute( new Runnable() {
@Override
public void run() {
try {
int response = postData("http://localhost:7001/test", makePayload( Math.max(1, rnd.nextInt( 1024 ) ) ) );
if( response != 200 ) {
errors.addAndGet( 1 );
}
}
catch( Exception e ) {
errors.addAndGet( 1 ); }
}
});
Thread.sleep( rnd.nextInt( 100 ) );
}
//aid netty leak detection
System.gc();
for( int i = 0; i < 100; ++i ) {
try {
//do not exceeded Netty content length ~1M
int response = postData("http://localhost:7001/test", makePayload( Math.max(1, rnd.nextInt( 127 * 1024 ) ) ) );
if( response != 200 ) {
errors.addAndGet( 1 );
}
}
catch( Exception e ) {
errors.addAndGet( 1 );
}
//aid netty leak detection
System.gc();
}
service.shutdown();
service.awaitTermination( 100, TimeUnit.SECONDS );
assertEquals( "Errors: ", 0, errors.intValue() );
}
}