Skip to content

Commit 02f1f22

Browse files
committed
feat: add more tests
1 parent 602942a commit 02f1f22

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import Std.Internal.Http
2+
import Std.Internal.Async.TCP
3+
import Std.Time
4+
import Std.Data.Iterators
5+
6+
open Std.Internal.IO.Async
7+
open Std.Http
8+
open Std Iterators
9+
10+
def theTimeInTheFuture : Async ByteArray := do
11+
(← Sleep.mk 1000).wait
12+
return s!"?\n".toUTF8
13+
14+
def tick :=
15+
Iter.repeat (fun _ => ()) () |>.mapM (fun _ => theTimeInTheFuture)
16+
17+
def writeToStream (s : Body.ByteStream) {α : Type} [Iterator α Async ByteArray] [IteratorLoopPartial α Async Async]
18+
(i : Std.IterM (α := α) Async ByteArray) (count : Nat) : Async Unit := do
19+
let mut n := 0
20+
for b in i.allowNontermination do
21+
if n >= count then break
22+
s.writeChunk (Chunk.mk b #[("time", some (toString n))])
23+
n := n + 1
24+
s.close
25+
26+
/-- Convert an HTTP request to a byte array -/
27+
def requestToByteArray (req : Request (Array Chunk)) : IO ByteArray := Async.block do
28+
let mut data := String.toUTF8 <| toString req.head
29+
for part in req.body do data := data ++ part.data
30+
return data
31+
32+
/-- Send a request through a mock connection and return the response data -/
33+
def sendRequest (client : Mock.Client) (server : Mock.Server) (req : Request (Array Chunk))
34+
(onRequest : Request Body → ContextAsync (Response Body)) : IO ByteArray := Async.block do
35+
let data ← requestToByteArray req
36+
37+
client.send data
38+
Std.Http.Server.serveConnection server onRequest (config := { lingeringTimeout := 3000, keepAliveTimeout := ⟨1000, by decide⟩ })
39+
|>.run (← Context.new)
40+
41+
let res ← client.recv?
42+
pure <| res.getD .empty
43+
44+
def testStreamingResponse : IO Unit := do
45+
let pair ← Mock.new
46+
let (client, server) := pair
47+
48+
let request := Request.new
49+
|>.method .get
50+
|>.uri! "/stream"
51+
|>.header! "Host" "localhost"
52+
|>.header! "Connection" "close"
53+
|>.body #[]
54+
55+
let response ← sendRequest client server request handle
56+
let responseData := String.fromUTF8! response
57+
58+
IO.println responseData.quote
59+
60+
-- Check that response starts with correct HTTP status line
61+
if !responseData.startsWith "HTTP/1.1 200 OK\x0d\n" then
62+
throw <| IO.userError "Response should start with HTTP/1.1 200 OK"
63+
64+
-- Check that Transfer-Encoding header is present (for streaming)
65+
if !responseData.contains "Transfer-Encoding: chunked" then
66+
throw <| IO.userError "Response should use chunked transfer encoding"
67+
68+
-- Check that we got multiple chunks (at least 3 time stamps)
69+
let bodyStart := responseData.splitOn "\x0d\n\x0d\n"
70+
if bodyStart.length < 2 then
71+
throw <| IO.userError "Response should have headers and body"
72+
where
73+
handle (_req : Request Body) : ContextAsync (Response Body) :=
74+
Response.new
75+
|>.status .ok
76+
|>.stream (writeToStream · tick 3)
77+
78+
/--
79+
info: "HTTP/1.1 200 OK\x0d\nTransfer-Encoding: chunked\x0d\nConnection: close\x0d\nServer: LeanHTTP/1.1\x0d\n\x0d\n2;time=0\x0d\n?\n\x0d\n2;time=1\x0d\n?\n\x0d\n2;time=2\x0d\n?\n\x0d\n0\x0d\n\x0d\n"
80+
-/
81+
#guard_msgs in
82+
#eval testStreamingResponse
83+
84+
/-- Test that without Connection: close, the server waits and times out -/
85+
def testTimeout : IO Unit := do
86+
let pair ← Mock.new
87+
let (client, server) := pair
88+
89+
-- Request WITHOUT Connection: close header
90+
let request := Request.new
91+
|>.method .get
92+
|>.uri! "/stream"
93+
|>.header! "Host" "localhost"
94+
|>.body #[]
95+
96+
let response ← sendRequest client server request handle
97+
let responseData := String.fromUTF8! response
98+
99+
IO.println responseData.quote
100+
where
101+
handle (_req : Request Body) : ContextAsync (Response Body) :=
102+
return Response.new
103+
|>.status .ok
104+
|>.build
105+
106+
/--
107+
info: "HTTP/1.1 200 OK\x0d\nContent-Length: 0\x0d\nServer: LeanHTTP/1.1\x0d\n\x0d\n"
108+
-/
109+
#guard_msgs in
110+
#eval testTimeout

0 commit comments

Comments
 (0)