#7281 add more tests and fix shortcomings

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2021-12-17 12:06:20 +01:00
parent ec9846c116
commit 1682265a00
3 changed files with 279 additions and 9 deletions

View File

@ -352,13 +352,26 @@ class AsyncContentProducer implements ContentProducer
_transformedContent = _rawContent;
}
if (_transformedContent != null && _transformedContent.isEmpty())
if (_transformedContent != null)
{
if (_transformedContent != _rawContent)
_transformedContent.succeeded();
if (LOG.isDebugEnabled())
LOG.debug("nulling depleted transformed content {}", this);
_transformedContent = null;
if (_transformedContent.isSpecial())
{
if (_transformedContent != _rawContent)
{
if (LOG.isDebugEnabled())
LOG.debug("making special transformed content the new raw content {}", this);
_rawContent.succeeded();
_rawContent = _transformedContent;
}
}
else if (_transformedContent.isEmpty())
{
if (_transformedContent != _rawContent)
_transformedContent.succeeded();
if (LOG.isDebugEnabled())
LOG.debug("nulling depleted transformed content {}", this);
_transformedContent = null;
}
}
if (_transformedContent == null)
@ -366,7 +379,7 @@ class AsyncContentProducer implements ContentProducer
if (_rawContent.isSpecial())
{
if (LOG.isDebugEnabled())
LOG.debug("using special raw content as transformed content {}", this);
LOG.debug("checking if special raw content should be refreshed {}", this);
// In case the _rawContent was set by consumeAll(), check the httpChannel
// to see if it has a more precise error. Otherwise, the exact same
@ -382,7 +395,6 @@ class AsyncContentProducer implements ContentProducer
LOG.debug("refreshed raw content: {} {}", _rawContent, this);
}
_transformedContent = _rawContent;
break;
}
else if (_rawContent.isEmpty())
@ -433,7 +445,7 @@ class AsyncContentProducer implements ContentProducer
Response response = _httpChannel.getResponse();
if (response.isCommitted())
_httpChannel.abort(failure);
return null;
return _transformedContent;
}
}

View File

@ -25,6 +25,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.io.ArrayByteBufferPool;
@ -188,6 +189,96 @@ public class AsyncContentProducerTest
assertThat(interceptor.contents.get(3).getError().getMessage(), is("testAsyncContentProducerErrorContentIsPassedToInterceptor error"));
}
@Test
public void testAsyncContentProducerInterceptorGeneratesError()
{
AtomicInteger contentSucceededCount = new AtomicInteger();
ContentProducer contentProducer = new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void succeeded()
{
contentSucceededCount.incrementAndGet();
}
}));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content -> new HttpInput.ErrorContent(new Throwable("testAsyncContentProducerInterceptorGeneratesError interceptor error")));
assertThat(contentProducer.isReady(), is(true));
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), is(true));
assertThat(content1.getError().getMessage(), is("testAsyncContentProducerInterceptorGeneratesError interceptor error"));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), is(true));
assertThat(content2.getError().getMessage(), is("testAsyncContentProducerInterceptorGeneratesError interceptor error"));
}
assertThat(contentSucceededCount.get(), is(1));
}
@Test
public void testAsyncContentProducerInterceptorGeneratesEof()
{
AtomicInteger contentSucceededCount = new AtomicInteger();
ContentProducer contentProducer = new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void succeeded()
{
contentSucceededCount.incrementAndGet();
}
}));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content -> new HttpInput.EofContent());
assertThat(contentProducer.isReady(), is(true));
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), is(true));
assertThat(content1.isEof(), is(true));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), is(true));
assertThat(content2.isEof(), is(true));
}
assertThat(contentSucceededCount.get(), is(1));
}
@Test
public void testAsyncContentProducerInterceptorThrows()
{
AtomicInteger contentFailedCount = new AtomicInteger();
ContentProducer contentProducer = new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void failed(Throwable x)
{
contentFailedCount.incrementAndGet();
}
}));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content ->
{
throw new RuntimeException("testAsyncContentProducerInterceptorThrows error");
});
assertThat(contentProducer.isReady(), is(true));
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), is(true));
assertThat(content1.getError().getCause().getMessage(), is("testAsyncContentProducerInterceptorThrows error"));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), is(true));
assertThat(content1.getError().getCause().getMessage(), is("testAsyncContentProducerInterceptorThrows error"));
}
assertThat(contentFailedCount.get(), is(1));
}
@Test
public void testAsyncContentProducerGzipInterceptor() throws Exception
{
@ -361,6 +452,47 @@ public class AsyncContentProducerTest
}
}
private static class StaticContentHttpChannel extends HttpChannel
{
private final HttpInput.Content content;
public StaticContentHttpChannel(HttpInput.Content content)
{
super(new MockConnector(), new HttpConfiguration(), null, null);
this.content = content;
}
@Override
public boolean needContent()
{
return true;
}
@Override
public HttpInput.Content produceContent()
{
return content;
}
@Override
public boolean failAllContent(Throwable failure)
{
return false;
}
@Override
public boolean failed(Throwable failure)
{
return false;
}
@Override
protected boolean eof()
{
return false;
}
}
private static class ArrayDelayedHttpChannel extends HttpChannel
{
private final ByteBuffer[] byteBuffers;

View File

@ -22,6 +22,7 @@ import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPOutputStream;
import org.eclipse.jetty.io.ArrayByteBufferPool;
@ -118,6 +119,90 @@ public class BlockingContentProducerTest
}
}
@Test
public void testBlockingContentProducerInterceptorGeneratesError()
{
AtomicInteger contentSucceededCount = new AtomicInteger();
ContentProducer contentProducer = new BlockingContentProducer(new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void succeeded()
{
contentSucceededCount.incrementAndGet();
}
})));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content -> new HttpInput.ErrorContent(new Throwable("testBlockingContentProducerInterceptorGeneratesError interceptor error")));
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), Matchers.is(true));
assertThat(content1.getError().getMessage(), Matchers.is("testBlockingContentProducerInterceptorGeneratesError interceptor error"));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), Matchers.is(true));
assertThat(content2.getError().getMessage(), Matchers.is("testBlockingContentProducerInterceptorGeneratesError interceptor error"));
}
assertThat(contentSucceededCount.get(), Matchers.is(1));
}
@Test
public void testBlockingContentProducerInterceptorGeneratesEof()
{
AtomicInteger contentSucceededCount = new AtomicInteger();
ContentProducer contentProducer = new BlockingContentProducer(new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void succeeded()
{
contentSucceededCount.incrementAndGet();
}
})));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content -> new HttpInput.EofContent());
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), Matchers.is(true));
assertThat(content1.isEof(), Matchers.is(true));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), Matchers.is(true));
assertThat(content2.isEof(), Matchers.is(true));
}
assertThat(contentSucceededCount.get(), Matchers.is(1));
}
@Test
public void testBlockingContentProducerInterceptorThrows()
{
AtomicInteger contentFailedCount = new AtomicInteger();
ContentProducer contentProducer = new BlockingContentProducer(new AsyncContentProducer(new StaticContentHttpChannel(new HttpInput.Content(ByteBuffer.allocate(1))
{
@Override
public void failed(Throwable x)
{
contentFailedCount.incrementAndGet();
}
})));
try (AutoLock lock = contentProducer.lock())
{
contentProducer.setInterceptor(content ->
{
throw new RuntimeException("testBlockingContentProducerInterceptorThrows error");
});
HttpInput.Content content1 = contentProducer.nextContent();
assertThat(content1.isSpecial(), Matchers.is(true));
assertThat(content1.getError().getCause().getMessage(), Matchers.is("testBlockingContentProducerInterceptorThrows error"));
HttpInput.Content content2 = contentProducer.nextContent();
assertThat(content2.isSpecial(), Matchers.is(true));
assertThat(content1.getError().getCause().getMessage(), Matchers.is("testBlockingContentProducerInterceptorThrows error"));
}
assertThat(contentFailedCount.get(), Matchers.is(1));
}
@Test
public void testBlockingContentProducerEofContentIsPassedToInterceptor() throws Exception
{
@ -371,6 +456,47 @@ public class BlockingContentProducerTest
}
}
private static class StaticContentHttpChannel extends HttpChannel
{
private final HttpInput.Content content;
public StaticContentHttpChannel(HttpInput.Content content)
{
super(new MockConnector(), new HttpConfiguration(), null, null);
this.content = content;
}
@Override
public boolean needContent()
{
return true;
}
@Override
public HttpInput.Content produceContent()
{
return content;
}
@Override
public boolean failAllContent(Throwable failure)
{
return false;
}
@Override
public boolean failed(Throwable failure)
{
return false;
}
@Override
protected boolean eof()
{
return false;
}
}
private static class ArrayDelayedHttpChannel extends HttpChannel
{
private final ByteBuffer[] byteBuffers;