Improve QPACK testing for instruction parsers.
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
b2a91fdbaf
commit
684272e1ae
|
@ -16,8 +16,6 @@ package org.eclipse.jetty.http3.qpack;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.http3.qpack.internal.parser.DecoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.parser.DecoderInstructionParser;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -39,10 +37,30 @@ public class DecoderInstructionParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddWithReferencedEntry() throws Exception
|
public void testSetDynamicTableCapacityInstruction() throws Exception
|
||||||
{
|
{
|
||||||
String insertAuthorityEntry = "c00f7777772e6578616d706c652e636f6d";
|
// Set Dynamic Table Capacity=220.
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertAuthorityEntry));
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("3fbd 01");
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
assertThat(_handler.setCapacities.poll(), is(220));
|
||||||
|
assertTrue(_handler.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDuplicateInstruction() throws Exception
|
||||||
|
{
|
||||||
|
// Duplicate (Relative Index = 2).
|
||||||
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("02");
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
assertThat(_handler.duplicates.poll(), is(2));
|
||||||
|
assertTrue(_handler.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertNameWithReferenceInstruction() throws Exception
|
||||||
|
{
|
||||||
|
// Insert With Name Reference to Static Table, Index=0 (:authority=www.example.com).
|
||||||
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("c00f 7777 772e 6578 616d 706c 652e 636f 6d");
|
||||||
_instructionParser.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
DecoderParserDebugHandler.ReferencedEntry entry = _handler.referencedNameEntries.poll();
|
DecoderParserDebugHandler.ReferencedEntry entry = _handler.referencedNameEntries.poll();
|
||||||
assertNotNull(entry);
|
assertNotNull(entry);
|
||||||
|
@ -50,8 +68,8 @@ public class DecoderInstructionParserTest
|
||||||
assertThat(entry.dynamic, is(false));
|
assertThat(entry.dynamic, is(false));
|
||||||
assertThat(entry.value, is("www.example.com"));
|
assertThat(entry.value, is("www.example.com"));
|
||||||
|
|
||||||
String insertPathEntry = "c10c2f73616d706c652f70617468";
|
// Insert With Name Reference to Static Table, Index=1 (:path=/sample/path).
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(insertPathEntry));
|
buffer = QpackTestUtil.hexToBuffer("c10c 2f73 616d 706c 652f 7061 7468");
|
||||||
_instructionParser.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
entry = _handler.referencedNameEntries.poll();
|
entry = _handler.referencedNameEntries.poll();
|
||||||
assertNotNull(entry);
|
assertNotNull(entry);
|
||||||
|
@ -61,12 +79,19 @@ public class DecoderInstructionParserTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetCapacity() throws Exception
|
public void testInsertWithLiteralNameInstruction() throws Exception
|
||||||
{
|
{
|
||||||
String setCapacityString = "3fbd01";
|
// Insert With Literal Name (custom-key=custom-value).
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(setCapacityString));
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("4a63 7573 746f 6d2d 6b65 790c 6375 7374 6f6d 2d76 616c 7565");
|
||||||
_instructionParser.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(_handler.setCapacities.poll(), is(220));
|
|
||||||
|
// We received the instruction correctly.
|
||||||
|
DecoderParserDebugHandler.LiteralEntry entry = _handler.literalNameEntries.poll();
|
||||||
|
assertNotNull(entry);
|
||||||
|
assertThat(entry.name, is("custom-key"));
|
||||||
|
assertThat(entry.value, is("custom-value"));
|
||||||
|
|
||||||
|
// There are no other instructions received.
|
||||||
assertTrue(_handler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl
|
||||||
{
|
{
|
||||||
public Queue<Integer> setCapacities = new LinkedList<>();
|
public Queue<Integer> setCapacities = new LinkedList<>();
|
||||||
public Queue<Integer> duplicates = new LinkedList<>();
|
public Queue<Integer> duplicates = new LinkedList<>();
|
||||||
public Queue<Entry> literalNameEntries = new LinkedList<>();
|
public Queue<LiteralEntry> literalNameEntries = new LinkedList<>();
|
||||||
public Queue<ReferencedEntry> referencedNameEntries = new LinkedList<>();
|
public Queue<ReferencedEntry> referencedNameEntries = new LinkedList<>();
|
||||||
|
|
||||||
private final QpackDecoder _decoder;
|
private final QpackDecoder _decoder;
|
||||||
|
@ -37,30 +37,30 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl
|
||||||
_decoder = decoder;
|
_decoder = decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Entry
|
public static class LiteralEntry
|
||||||
{
|
{
|
||||||
public Entry(String name, String value)
|
public String name;
|
||||||
|
public String value;
|
||||||
|
|
||||||
|
public LiteralEntry(String name, String value)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
String name;
|
|
||||||
String value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReferencedEntry
|
public static class ReferencedEntry
|
||||||
{
|
{
|
||||||
|
public int index;
|
||||||
|
public boolean dynamic;
|
||||||
|
public String value;
|
||||||
|
|
||||||
public ReferencedEntry(int index, boolean dynamic, String value)
|
public ReferencedEntry(int index, boolean dynamic, String value)
|
||||||
{
|
{
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.dynamic = dynamic;
|
this.dynamic = dynamic;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index;
|
|
||||||
boolean dynamic;
|
|
||||||
String value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,7 +90,7 @@ public class DecoderParserDebugHandler implements DecoderInstructionParser.Handl
|
||||||
@Override
|
@Override
|
||||||
public void onInsertWithLiteralName(String name, String value) throws QpackException
|
public void onInsertWithLiteralName(String name, String value) throws QpackException
|
||||||
{
|
{
|
||||||
literalNameEntries.add(new Entry(name, value));
|
literalNameEntries.add(new LiteralEntry(name, value));
|
||||||
if (_decoder != null)
|
if (_decoder != null)
|
||||||
_decoder.insert(name, value);
|
_decoder.insert(name, value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import java.nio.ByteBuffer;
|
||||||
import org.eclipse.jetty.http3.qpack.internal.parser.EncoderInstructionParser;
|
import org.eclipse.jetty.http3.qpack.internal.parser.EncoderInstructionParser;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
@ -27,47 +27,53 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class EncoderInstructionParserTest
|
public class EncoderInstructionParserTest
|
||||||
{
|
{
|
||||||
|
private EncoderParserDebugHandler _handler;
|
||||||
|
private EncoderInstructionParser _instructionParser;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before()
|
||||||
|
{
|
||||||
|
_handler = new EncoderParserDebugHandler();
|
||||||
|
_instructionParser = new EncoderInstructionParser(_handler);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSectionAcknowledgement() throws Exception
|
public void testSectionAcknowledgement() throws Exception
|
||||||
{
|
{
|
||||||
EncoderParserDebugHandler debugHandler = new EncoderParserDebugHandler();
|
|
||||||
EncoderInstructionParser incomingEncoderStream = new EncoderInstructionParser(debugHandler);
|
|
||||||
|
|
||||||
// Example from the spec, section acknowledgement instruction with stream id 4.
|
// Example from the spec, section acknowledgement instruction with stream id 4.
|
||||||
String encoded = "84";
|
String encoded = "84";
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
ByteBuffer buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
incomingEncoderStream.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(4));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(4));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
|
|
||||||
// 1111 1110 == FE is largest value we can do without continuation should be stream ID 126.
|
// 1111 1110 == FE is largest value we can do without continuation should be stream ID 126.
|
||||||
encoded = "FE";
|
encoded = "FE";
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
incomingEncoderStream.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(126));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(126));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
|
|
||||||
// 1111 1111 0000 0000 == FF00 is next value, stream id 127.
|
// 1111 1111 0000 0000 == FF00 is next value, stream id 127.
|
||||||
encoded = "FF00";
|
encoded = "FF00";
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
incomingEncoderStream.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(127));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(127));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
|
|
||||||
// 1111 1111 0000 0001 == FF01 is next value, stream id 128.
|
// 1111 1111 0000 0001 == FF01 is next value, stream id 128.
|
||||||
encoded = "FF01";
|
encoded = "FF01";
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
incomingEncoderStream.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(128));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(128));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
|
|
||||||
// FFBA09 contains section ack with stream ID of 1337, this contains an octet with continuation bit.
|
// FFBA09 contains section ack with stream ID of 1337, this contains an octet with continuation bit.
|
||||||
encoded = "FFBA09";
|
encoded = "FFBA09";
|
||||||
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
buffer = BufferUtil.toBuffer(TypeUtil.fromHexString(encoded));
|
||||||
incomingEncoderStream.parse(buffer);
|
_instructionParser.parse(buffer);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(1337));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
|
|
||||||
// Test with continuation.
|
// Test with continuation.
|
||||||
encoded = "FFBA09";
|
encoded = "FFBA09";
|
||||||
|
@ -76,27 +82,31 @@ public class EncoderInstructionParserTest
|
||||||
{
|
{
|
||||||
ByteBuffer buffer1 = BufferUtil.toBuffer(bytes, 0, 2);
|
ByteBuffer buffer1 = BufferUtil.toBuffer(bytes, 0, 2);
|
||||||
ByteBuffer buffer2 = BufferUtil.toBuffer(bytes, 2, 1);
|
ByteBuffer buffer2 = BufferUtil.toBuffer(bytes, 2, 1);
|
||||||
incomingEncoderStream.parse(buffer1);
|
_instructionParser.parse(buffer1);
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
incomingEncoderStream.parse(buffer2);
|
_instructionParser.parse(buffer2);
|
||||||
assertThat(debugHandler.sectionAcknowledgements.poll(), is(1337));
|
assertThat(_handler.sectionAcknowledgements.poll(), is(1337));
|
||||||
assertTrue(debugHandler.isEmpty());
|
assertTrue(_handler.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@Test
|
@Test
|
||||||
public void testStreamCancellation() throws Exception
|
public void testStreamCancellation() throws Exception
|
||||||
{
|
{
|
||||||
// TODO: Write this test.
|
// Stream Cancellation (Stream=8).
|
||||||
throw new RuntimeException("TODO: testStreamCancellation");
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("48");
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
assertThat(_handler.streamCancellations.poll(), is(8));
|
||||||
|
assertTrue(_handler.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Disabled
|
|
||||||
@Test
|
@Test
|
||||||
public void testInsertCountIncrement() throws Exception
|
public void testInsertCountIncrement() throws Exception
|
||||||
{
|
{
|
||||||
// TODO: Write this test.
|
// Insert Count Increment (1).
|
||||||
throw new RuntimeException("TODO: testInsertCountIncrement");
|
ByteBuffer buffer = QpackTestUtil.hexToBuffer("01");
|
||||||
|
_instructionParser.parse(buffer);
|
||||||
|
assertThat(_handler.insertCountIncrements.poll(), is(1));
|
||||||
|
assertTrue(_handler.isEmpty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue