package org.jooby.internal.jetty;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.isA;
import static org.junit.Assert.assertArrayEquals;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.jooby.servlet.ServletServletRequest;
import org.jooby.test.MockUnit;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RunWith(PowerMockRunner.class)
@PrepareForTest({JettyResponse.class, Channels.class, LoggerFactory.class })
public class JettyResponseTest {
private MockUnit.Block servletRequest = unit -> {
Request req = unit.get(Request.class);
ServletServletRequest request = unit.get(ServletServletRequest.class);
expect(request.servletRequest()).andReturn(req);
};
private MockUnit.Block startAsync = unit -> {
ServletServletRequest request = unit.get(ServletServletRequest.class);
HttpServletRequest req = unit.mock(HttpServletRequest.class);
expect(req.isAsyncStarted()).andReturn(false);
expect(req.startAsync()).andReturn(unit.get(AsyncContext.class));
expect(request.servletRequest()).andReturn(req);
};
private MockUnit.Block asyncStarted = unit -> {
Request request = unit.get(Request.class);
expect(request.isAsyncStarted()).andReturn(true);
};
private MockUnit.Block noAsyncStarted = unit -> {
Request request = unit.get(Request.class);
expect(request.isAsyncStarted()).andReturn(false);
};
@Test
public void defaults() throws Exception {
new MockUnit(ServletServletRequest.class, Request.class, Response.class)
.expect(servletRequest)
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class));
});
}
@Test
public void sendBytes() throws Exception {
byte[] bytes = "bytes".getBytes();
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(unit.capture(ByteBuffer.class));
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.send(bytes);
}, unit -> {
assertArrayEquals(bytes, unit.captured(ByteBuffer.class).iterator().next().array());
});
}
@Test
public void sendBuffer() throws Exception {
byte[] bytes = "bytes".getBytes();
ByteBuffer buffer = ByteBuffer.wrap(bytes);
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(buffer));
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.send(buffer);
});
}
@Test
public void sendInputStream() throws Exception {
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
InputStream.class, AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
unit.mockStatic(Channels.class);
ReadableByteChannel channel = unit.mock(ReadableByteChannel.class);
expect(Channels.newChannel(unit.get(InputStream.class))).andReturn(channel);
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(channel), isA(JettyResponse.class));
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(startAsync)
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.send(unit.get(InputStream.class));
});
}
@Test
public void sendInputStreamAsyncStarted() throws Exception {
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
InputStream.class, AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
unit.mockStatic(Channels.class);
ReadableByteChannel channel = unit.mock(ReadableByteChannel.class);
expect(Channels.newChannel(unit.get(InputStream.class))).andReturn(channel);
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(channel), isA(JettyResponse.class));
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(unit -> {
ServletServletRequest request = unit.get(ServletServletRequest.class);
HttpServletRequest req = unit.mock(HttpServletRequest.class);
expect(req.isAsyncStarted()).andReturn(true);
expect(request.servletRequest()).andReturn(req);
})
.run(unit -> {
JettyResponse rsp = new JettyResponse(unit.get(ServletServletRequest.class),
unit.get(Response.class));
rsp.send(unit.get(InputStream.class));
rsp.end();
});
}
@Test
public void sendSmallFileChannel() throws Exception {
FileChannel channel = newFileChannel(1);
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(channel));
Response rsp = unit.get(Response.class);
expect(rsp.getBufferSize()).andReturn(2);
expect(rsp.getHttpOutput()).andReturn(output);
})
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.send(channel);
});
}
@Test
public void sendLargeFileChannel() throws Exception {
FileChannel channel = newFileChannel(10);
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(channel), isA(JettyResponse.class));
Response rsp = unit.get(Response.class);
expect(rsp.getBufferSize()).andReturn(5);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(startAsync)
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.send(channel);
});
}
@Test
public void succeeded() throws Exception {
byte[] bytes = "bytes".getBytes();
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(unit.capture(ByteBuffer.class));
output.close();
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output).times(2);
})
.expect(noAsyncStarted)
.run(unit -> {
JettyResponse rsp = new JettyResponse(unit.get(ServletServletRequest.class),
unit.get(Response.class));
rsp.send(bytes);
rsp.succeeded();
});
}
@Test
public void succeededAsync() throws Exception {
FileChannel channel = newFileChannel(10);
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class,
AsyncContext.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.sendContent(eq(channel), isA(JettyResponse.class));
Response rsp = unit.get(Response.class);
expect(rsp.getBufferSize()).andReturn(5);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(startAsync)
.expect(asyncStarted)
.expect(unit -> {
Request req = unit.get(Request.class);
AsyncContext ctx = unit.get(AsyncContext.class);
ctx.complete();
expect(req.getAsyncContext()).andReturn(ctx);
})
.run(unit -> {
JettyResponse rsp = new JettyResponse(unit.get(ServletServletRequest.class),
unit.get(Response.class));
rsp.send(channel);
rsp.succeeded();
});
}
@Test
public void end() throws Exception {
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class)
.expect(servletRequest)
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.close();
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(noAsyncStarted)
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.end();
});
}
@Test
public void failed() throws Exception {
IOException cause = new IOException();
new MockUnit(ServletServletRequest.class, Request.class, Response.class, HttpOutput.class)
.expect(servletRequest)
.expect(unit -> {
Logger log = unit.mock(Logger.class);
log.error("execution of /path resulted in exception", cause);
unit.mockStatic(LoggerFactory.class);
expect(LoggerFactory.getLogger(org.jooby.Response.class)).andReturn(log);
})
.expect(unit -> {
HttpOutput output = unit.get(HttpOutput.class);
output.close();
Response rsp = unit.get(Response.class);
expect(rsp.getHttpOutput()).andReturn(output);
})
.expect(noAsyncStarted)
.expect(unit -> {
ServletServletRequest req = unit.get(ServletServletRequest.class);
expect(req.path()).andReturn("/path");
})
.run(unit -> {
new JettyResponse(unit.get(ServletServletRequest.class), unit.get(Response.class))
.failed(cause);
});
}
private FileChannel newFileChannel(final int size) {
return new FileChannel() {
@Override
public int read(final ByteBuffer dst) throws IOException {
return 0;
}
@Override
public long read(final ByteBuffer[] dsts, final int offset, final int length)
throws IOException {
return 0;
}
@Override
public int write(final ByteBuffer src) throws IOException {
return 0;
}
@Override
public long write(final ByteBuffer[] srcs, final int offset, final int length)
throws IOException {
return 0;
}
@Override
public long position() throws IOException {
return 0;
}
@Override
public FileChannel position(final long newPosition) throws IOException {
return null;
}
@Override
public long size() throws IOException {
return size;
}
@Override
public FileChannel truncate(final long size) throws IOException {
return null;
}
@Override
public void force(final boolean metaData) throws IOException {
}
@Override
public long transferTo(final long position, final long count,
final WritableByteChannel target)
throws IOException {
return 0;
}
@Override
public long transferFrom(final ReadableByteChannel src, final long position, final long count)
throws IOException {
return 0;
}
@Override
public int read(final ByteBuffer dst, final long position) throws IOException {
return 0;
}
@Override
public int write(final ByteBuffer src, final long position) throws IOException {
return 0;
}
@Override
public MappedByteBuffer map(final MapMode mode, final long position, final long size)
throws IOException {
return null;
}
@Override
public FileLock lock(final long position, final long size, final boolean shared)
throws IOException {
return null;
}
@Override
public FileLock tryLock(final long position, final long size, final boolean shared)
throws IOException {
return null;
}
@Override
protected void implCloseChannel() throws IOException {
}
};
}
}