Livt packages
Livt.Web
Version 1.0.0
Bounded HTTP routing, request parsing, response encoding, and Ethernet application composition for Livt.
Published files (63)
- CounterContent.lvt
- HttpApplicationTest.lvt
- HttpHandlerTest.lvt
- HttpHeaderRangeData.lvt
- HttpHeaderRangeTest.lvt
- HttpNetworkEndpointTest.lvt
- HttpPathTest.lvt
- HttpRequestBoundsTest.lvt
- HttpRequestParserTest.lvt
- HttpRequestTestData.lvt
- HttpResponseEncoderTest.lvt
- HttpResponseTestData.lvt
- HttpRoutingTest.lvt
- HttpTcpSequenceTest.lvt
- RoutingBytes.lvt
- RoutingCounter.lvt
tests/http/HttpRoutingTest.lvt
namespace Livt.Web.Tests.Http
using Livt.Net
using Livt.Web.Http
@Test
component HttpRoutingTest
{
const WIRE[547] = [
0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4F, 0x4B, 0x0D,
0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x74,
0x65, 0x78, 0x74, 0x2F, 0x68, 0x74, 0x6D, 0x6C, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E,
0x74, 0x2D, 0x4C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x3A, 0x20, 0x34, 0x0D, 0x0A, 0x43, 0x6F, 0x6E,
0x6E, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x0D, 0x0A,
0x0D, 0x0A, 0x48, 0x4F, 0x4D, 0x45, 0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20, 0x32,
0x30, 0x30, 0x20, 0x4F, 0x4B, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x54,
0x79, 0x70, 0x65, 0x3A, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E,
0x2F, 0x6A, 0x73, 0x6F, 0x6E, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x4C,
0x65, 0x6E, 0x67, 0x74, 0x68, 0x3A, 0x20, 0x33, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63,
0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x5B,
0x37, 0x5D, 0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20, 0x34, 0x30, 0x34, 0x20, 0x4E,
0x6F, 0x74, 0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E,
0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, 0x61,
0x69, 0x6E, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x4C, 0x65, 0x6E, 0x67,
0x74, 0x68, 0x3A, 0x20, 0x31, 0x30, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69,
0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x4E, 0x6F, 0x74,
0x20, 0x46, 0x6F, 0x75, 0x6E, 0x64, 0x0A, 0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20,
0x34, 0x30, 0x35, 0x20, 0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x20, 0x4E, 0x6F, 0x74, 0x20, 0x41,
0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D,
0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, 0x61, 0x69, 0x6E,
0x0D, 0x0A, 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x3A, 0x20, 0x47, 0x45, 0x54, 0x2C, 0x20, 0x48, 0x45,
0x41, 0x44, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x4C, 0x65, 0x6E, 0x67,
0x74, 0x68, 0x3A, 0x20, 0x31, 0x39, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69,
0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x0D, 0x0A, 0x4D, 0x65, 0x74,
0x68, 0x6F, 0x64, 0x20, 0x4E, 0x6F, 0x74, 0x20, 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x0A,
0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x30, 0x20, 0x34, 0x30, 0x35, 0x20, 0x4D, 0x65, 0x74,
0x68, 0x6F, 0x64, 0x20, 0x4E, 0x6F, 0x74, 0x20, 0x41, 0x6C, 0x6C, 0x6F, 0x77, 0x65, 0x64, 0x0D,
0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x54, 0x79, 0x70, 0x65, 0x3A, 0x20, 0x74,
0x65, 0x78, 0x74, 0x2F, 0x70, 0x6C, 0x61, 0x69, 0x6E, 0x0D, 0x0A, 0x41, 0x6C, 0x6C, 0x6F, 0x77,
0x3A, 0x20, 0x47, 0x45, 0x54, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2D, 0x4C,
0x65, 0x6E, 0x67, 0x74, 0x68, 0x3A, 0x20, 0x31, 0x39, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x6E, 0x65,
0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x63, 0x6C, 0x6F, 0x73, 0x65, 0x0D, 0x0A, 0x0D, 0x0A,
0x4D, 0x65, 0x74, 0x68, 0x6F, 0x64, 0x20, 0x4E, 0x6F, 0x74, 0x20, 0x41, 0x6C, 0x6C, 0x6F, 0x77,
0x65, 0x64, 0x0A]
source: RoutingBytes
rootPath: RoutingBytes
statusPath: RoutingBytes
aboutPath: RoutingBytes
body: RoutingBytes
aboutBody: RoutingBytes
headBody: RoutingBytes
request: HttpRequestParser<RoutingBytes>
rootMatch: HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>
statusMatch: HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>
aboutMatch: HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>
counter: RoutingCounter
dynamic: CounterContent
duplicateContent: CounterContent
home: StaticContent<RoutingBytes>
headContent: StaticContent<RoutingBytes>
aboutContent: StaticContent<RoutingBytes>
root: Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>
head: Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>
status: Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>
duplicate: Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>
about: Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>
pair: RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>
tail: RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>
branch: RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>
routes: RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>
router: HttpRouter<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>>
encoder: HttpResponseEncoder<HttpRouter<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>>>
new()
{
source = new RoutingBytes()
rootPath = new RoutingBytes()
statusPath = new RoutingBytes()
aboutPath = new RoutingBytes()
body = new RoutingBytes()
aboutBody = new RoutingBytes()
headBody = new RoutingBytes()
request = new HttpRequestParser<RoutingBytes>(source)
rootMatch = new HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>(request, rootPath)
statusMatch = new HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>(request, statusPath)
aboutMatch = new HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>(request, aboutPath)
counter = new RoutingCounter()
dynamic = new CounterContent(counter)
duplicateContent = new CounterContent(counter)
home = new StaticContent<RoutingBytes>(body, HttpContentType.Html)
headContent = new StaticContent<RoutingBytes>(headBody, HttpContentType.PlainText)
aboutContent = new StaticContent<RoutingBytes>(aboutBody, HttpContentType.PlainText)
root = new Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>(HttpMethod.Get, request, rootMatch, home)
head = new Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>(HttpMethod.Head, request, statusMatch, headContent)
status = new Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>(HttpMethod.Get, request, statusMatch, dynamic)
duplicate = new Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>(HttpMethod.Get, request, statusMatch, duplicateContent)
about = new Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>(HttpMethod.Get, request, aboutMatch, aboutContent)
pair = new RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>(head, status)
tail = new RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>(duplicate, about)
branch = new RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>(pair, tail)
routes = new RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>(root, branch)
router = new HttpRouter<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>>(routes)
encoder = new HttpResponseEncoder<HttpRouter<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, RouteChain<RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>>, RouteChain<Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, CounterContent>, Route<HttpRequestParser<RoutingBytes>, HttpPath<HttpRequestParser<RoutingBytes>, RoutingBytes>, StaticContent<RoutingBytes>>>>>>>(router)
}
fn Select(requestId: int)
{
encoder.Invalidate()
router.End()
request.Invalidate()
source.Select(requestId)
rootPath.Select(0)
statusPath.Select(1)
aboutPath.Select(2)
body.Select(44)
aboutBody.Select(45)
headBody.Select(46)
counter.Set(7)
dynamic.ResetCounts()
duplicateContent.ResetCounts()
assert request.TryParse() == HttpRequestResult.Ready
}
fn CheckWire(offset: int, length: int)
{
assert encoder.TryPrepare(512)
assert encoder.GetAvailableLength() == length
for (var i: int = 0; i < length; i++) {
var value: byte = 0xFF
assert encoder.TryRead(i, value) == PacketDataResult.Success
assert value == WIRE[offset + i]
}
}
@Test
fn RootResponse()
{
this.Select(25)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Prepared
this.CheckWire(0, 86)
assert dynamic.GetStarts() == 0
assert duplicateContent.GetStarts() == 0
}
@Test
fn LaterMethodAndNestedFirstMatch()
{
this.Select(26)
assert router.Poll() == HttpPreparation.Idle
assert router.Begin() == HttpPreparation.Idle
assert router.Select() == RouteDispatch.Selected
assert dynamic.GetStarts() == 0
assert router.Begin() == HttpPreparation.Pending
assert router.Begin() == HttpPreparation.Pending
assert router.Select() == RouteDispatch.Selected
assert router.Poll() == HttpPreparation.Pending
assert !router.IsReady()
assert !encoder.TryPrepare(512)
counter.Set(9)
assert router.Poll() == HttpPreparation.Prepared
assert router.Poll() == HttpPreparation.Prepared
assert router.Begin() == HttpPreparation.Prepared
assert dynamic.GetStarts() == 1
assert duplicateContent.GetStarts() == 0
this.CheckWire(86, 92)
encoder.Invalidate()
router.End()
router.End()
assert dynamic.GetEnds() == 1
assert duplicateContent.GetEnds() == 0
assert body.IsReady()
}
@Test
fn QueryMatchesStatus()
{
this.Select(27)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
assert router.Poll() == HttpPreparation.Pending
assert router.Poll() == HttpPreparation.Prepared
this.CheckWire(86, 92)
}
@Test
fn TrailingSlashFallsBack()
{
this.Select(28)
assert router.Select() == RouteDispatch.NotFound
assert router.Begin() == HttpPreparation.Prepared
this.CheckWire(178, 101)
assert dynamic.GetStarts() == 0
}
@Test
fn UnknownPathWithOtherMethodIs404()
{
this.Select(34)
assert router.Select() == RouteDispatch.NotFound
assert router.Begin() == HttpPreparation.Prepared
assert router.GetAllowedMethods() == HttpAllowedMethods.None
this.CheckWire(178, 101)
}
@Test
fn AllowUnionAndDeduplication()
{
this.Select(32)
assert router.Select() == RouteDispatch.MethodNotAllowed
assert router.Select() == RouteDispatch.MethodNotAllowed
assert router.Begin() == HttpPreparation.Prepared
assert router.GetAllowedMethods() == HttpAllowedMethods.GetAndHead
this.CheckWire(279, 137)
assert dynamic.GetStarts() == 0
assert duplicateContent.GetStarts() == 0
}
@Test
fn AllowOnlyIncludesMatchingPaths()
{
this.Select(33)
assert router.Select() == RouteDispatch.MethodNotAllowed
assert router.Begin() == HttpPreparation.Prepared
assert router.GetAllowedMethods() == HttpAllowedMethods.Get
this.CheckWire(416, 131)
}
@Test
fn HeadSelectsFirstMethodWithoutStartingGet()
{
this.Select(31)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Prepared
assert router.GetContentType() == HttpContentType.PlainText
assert dynamic.GetStarts() == 0
assert duplicateContent.GetStarts() == 0
// HEAD transport/body suppression is not implemented by the encoder.
}
@Test
fn HandlerFailureDoesNotFallThrough()
{
this.Select(26)
counter.Set(10)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Failed
counter.Set(7)
assert router.Begin() == HttpPreparation.Failed
assert router.Poll() == HttpPreparation.Failed
assert router.Select() == RouteDispatch.Selected
assert !router.IsReady()
assert router.GetStatus() == HttpStatus.Unknown
assert !encoder.TryPrepare(512)
assert dynamic.GetStarts() == 1
assert duplicateContent.GetStarts() == 0
}
@Test
fn PendingCancellationAndRestart()
{
this.Select(26)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
router.End()
router.End()
assert dynamic.GetStarts() == 1
assert dynamic.GetEnds() == 1
assert router.Poll() == HttpPreparation.Idle
assert !router.IsReady()
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
assert dynamic.GetStarts() == 2
}
@Test
fn MatcherFailureIsNot404()
{
this.Select(26)
statusPath.FailAt(0)
assert router.Select() == RouteDispatch.Failed
assert router.Begin() == HttpPreparation.Failed
assert !encoder.TryPrepare(512)
assert dynamic.GetStarts() == 0
}
@Test
fn EarlierMatchStopsScan()
{
this.Select(25)
statusPath.FailAt(0)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Prepared
assert statusPath.GetReads() == 0
this.CheckWire(0, 86)
}
@Test
fn NotReadyRetriesWithoutStartingHandler()
{
this.Select(26)
statusPath.Release()
assert router.Select() == RouteDispatch.NotReady
assert router.Begin() == HttpPreparation.Idle
assert dynamic.GetStarts() == 0
statusPath.Select(1)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
assert dynamic.GetStarts() == 1
}
@Test
fn FailureDuringEmissionClearsPublication()
{
this.Select(26)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
assert router.Poll() == HttpPreparation.Pending
assert router.Poll() == HttpPreparation.Prepared
assert encoder.TryPrepare(512)
dynamic.FailRead()
var headerLength = encoder.GetHeaderLength()
var value: byte = 0xFF
assert encoder.TryRead(headerLength, value) == PacketDataResult.Busy
assert value == 0x00
assert !router.IsReady()
assert !encoder.IsReady()
assert router.Poll() == HttpPreparation.Failed
assert router.GetAvailableLength() == 0
assert duplicateContent.GetStarts() == 0
}
@Test
fn CheckedResponseBounds()
{
this.Select(25)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Prepared
var value: byte = 0xFF
assert router.TryRead(-1, value) == PacketDataResult.Invalid
assert value == 0x00
assert router.TryRead(4, value) == PacketDataResult.Invalid
assert value == 0x00
assert router.IsReady()
encoder.Invalidate()
router.End()
assert router.TryRead(0, value) == PacketDataResult.NotReady
assert value == 0x00
}
@Test
fn ReuseAfterFallbackClearsDescendants()
{
this.Select(32)
assert router.Select() == RouteDispatch.MethodNotAllowed
assert router.Begin() == HttpPreparation.Prepared
router.End()
request.Invalidate()
source.Select(43)
assert request.TryParse() == HttpRequestResult.Ready
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Prepared
assert router.GetStatus() == HttpStatus.Ok
assert router.GetAllowedMethods() == HttpAllowedMethods.None
assert router.GetAvailableLength() == 5
}
@Test
fn DirectRouteBeginDoesNotPollPendingWork()
{
this.Select(26)
assert status.Select() == RouteDispatch.Selected
assert status.Begin() == HttpPreparation.Pending
assert status.Begin() == HttpPreparation.Pending
assert status.Begin() == HttpPreparation.Pending
assert status.Poll() == HttpPreparation.Pending
assert status.Poll() == HttpPreparation.Prepared
assert dynamic.GetStarts() == 1
status.End()
assert dynamic.GetEnds() == 1
}
@Test
fn CancelSelectionBeforeBegin()
{
this.Select(26)
assert router.Select() == RouteDispatch.Selected
router.End()
assert dynamic.GetStarts() == 0
assert dynamic.GetEnds() == 0
assert router.Poll() == HttpPreparation.Idle
}
@Test
fn UnpublishedRequestCanBeRetried()
{
this.Select(26)
request.Invalidate()
assert router.Select() == RouteDispatch.NotReady
assert rootPath.GetReads() == 0
assert router.Begin() == HttpPreparation.Idle
assert request.TryParse() == HttpRequestResult.Ready
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
assert dynamic.GetStarts() == 1
}
@Test
fn PendingHandlerFailureIsTerminal()
{
this.Select(26)
assert router.Select() == RouteDispatch.Selected
assert router.Begin() == HttpPreparation.Pending
dynamic.FailPreparation()
assert router.Poll() == HttpPreparation.Failed
assert router.Begin() == HttpPreparation.Failed
assert router.Poll() == HttpPreparation.Failed
assert dynamic.GetStarts() == 1
assert duplicateContent.GetStarts() == 0
assert !router.IsReady()
router.End()
assert dynamic.GetEnds() == 1
}
}