nim-websock/tests/testwebsockets.nim

1054 lines
28 KiB
Nim
Raw Normal View History

import std/[strutils, random], httputils
import pkg/[
asynctest,
chronos,
chronos/apps/http/httpserver,
chronicles,
stew/byteutils]
WIP: Implement websocket TLS. (#7) * Update http to use chronos http. * Implement TLS in websocket. * Add webscoket TLS test. * Minor nit. * Add TLS test file. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * merge master * wip * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Update http to use chronos http. * Implement TLS in websocket. * Minor nit. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * add testing keys * wip * fix test * wip * remove eth dep and add skipdirs * fix package structure * fix deps * check nim version * Fix CI failure. * Don't call `ws.stream.closeWait()` * always close both ends to complete the sequence * misc * don't fail on close * Fix windows CI. * fix linux x86 builds * use consistent connect pattern * move keys to better place * return dumbResponse * small cleanup Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com>
2021-04-13 22:05:58 +00:00
import ../ws/ws
var server: HttpServerRef
let address = initTAddress("127.0.0.1:8888")
proc rndStr*(size: int): string =
for _ in .. size:
add(result, char(rand(int('A') .. int('z'))))
2021-04-15 08:00:52 +00:00
proc rndBin*(size: int): seq[byte] =
for _ in .. size:
add(result, byte(rand(0 .. 255)))
proc waitForClose(ws: WSSession) {.async.} =
try:
while ws.readystate != ReadyState.Closed:
discard await ws.recv()
except CatchableError:
debug "Closing websocket"
suite "Test handshake":
teardown:
await server.stop()
await server.closeWait()
test "Test for incorrect protocol":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
expect WSProtoMismatchError:
discard await server.handleRequest(request)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
expect WSFailedUpgradeError:
discard await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["wrongproto"])
test "Test for incorrect version":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["ws"])
expect WSVersionError:
discard await server.handleRequest(request)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
expect WSFailedUpgradeError:
discard await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["wrongproto"],
version = 14)
test "Test for client headers":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
check request.headers.getString("Connection").toUpperAscii() ==
"Upgrade".toUpperAscii()
check request.headers.getString("Upgrade").toUpperAscii() ==
"websocket".toUpperAscii()
check request.headers.getString("Cache-Control").toUpperAscii() ==
"no-cache".toUpperAscii()
check request.headers.getString("Sec-WebSocket-Version") == $WSDefaultVersion
check request.headers.contains("Sec-WebSocket-Key")
discard await request.respond(Http200, "Connection established")
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
expect WSFailedUpgradeError:
discard await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
test "Test for incorrect scheme":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
expect WSProtoMismatchError:
var ws = await server.handleRequest(request)
check ws.readyState == ReadyState.Closed
return await request.respond(Http200, "Connection established")
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let uri = "wx://127.0.0.1:8888/ws"
expect WSWrongUriSchemeError:
discard await WebSocket.connect(
parseUri(uri),
protocols = @["proto"])
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
suite "Test transmission":
teardown:
await server.closeWait()
test "Send text message message with payload of length 65535":
let testString = rndStr(65535)
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
check string.fromBytes(servRes) == testString
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.send(testString)
await wsClient.close()
test "Server - test reading simple frame":
let testString = "Hello!"
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
check string.fromBytes(servRes) == testString
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.send(testString)
await wsClient.close()
test "Client - test reading simple frame":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
let testString = "Hello!"
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await ws.send(testString)
await ws.close()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
2021-05-22 09:04:40 +00:00
var clientRes = await wsClient.recv()
check string.fromBytes(clientRes) == testString
await waitForClose(wsClient)
WIP: Implement websocket TLS. (#7) * Update http to use chronos http. * Implement TLS in websocket. * Add webscoket TLS test. * Minor nit. * Add TLS test file. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * merge master * wip * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Update http to use chronos http. * Implement TLS in websocket. * Minor nit. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * add testing keys * wip * fix test * wip * remove eth dep and add skipdirs * fix package structure * fix deps * check nim version * Fix CI failure. * Don't call `ws.stream.closeWait()` * always close both ends to complete the sequence * misc * don't fail on close * Fix windows CI. * fix linux x86 builds * use consistent connect pattern * move keys to better place * return dumbResponse * small cleanup Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com>
2021-04-13 22:05:58 +00:00
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
suite "Test ping-pong":
teardown:
await server.closeWait()
test "Send text Message fragmented into 2 fragments, one ping with payload in-between":
var ping, pong = false
let testString = "1234567890"
let msg = toBytes(testString)
let maxFrameSize = 5
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
2021-05-22 09:04:40 +00:00
onPing = proc(data: openArray[byte]) =
ping = true
)
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let respData = await ws.recv()
check string.fromBytes(respData) == testString
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
frameSize = maxFrameSize,
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
)
let maskKey = genMaskKey(newRng())
await wsClient.stream.writer.write(
(await Frame(
fin: false,
rsv1: false,
rsv2: false,
rsv3: false,
opcode: Opcode.Text,
mask: true,
data: msg[0..4],
maskKey: maskKey)
.encode()))
await wsClient.ping()
await wsClient.stream.writer.write(
(await Frame(
fin: true,
rsv1: false,
rsv2: false,
rsv3: false,
opcode: Opcode.Cont,
mask: true,
data: msg[5..9],
maskKey: maskKey)
.encode()))
await wsClient.close()
check:
ping
pong
test "Server - test ping-pong control messages":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
var ping, pong = false
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
)
let ws = await server.handleRequest(request)
await ws.ping()
await ws.close()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
2021-05-22 09:04:40 +00:00
onPing = proc(data: openArray[byte]) =
ping = true
)
await waitForClose(wsClient)
check:
ping
pong
test "Client - test ping-pong control messages":
var ping, pong = false
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
2021-05-22 09:04:40 +00:00
onPing = proc(data: openArray[byte]) =
ping = true
)
let ws = await server.handleRequest(request)
await waitForClose(ws)
check:
ping
pong
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
)
await wsClient.ping()
await wsClient.close()
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
suite "Test framing":
teardown:
await server.closeWait()
test "should split message into frames":
let testString = "1234567890"
proc cb(r: RequestFence): Future[HttpResponseRef]{.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
let frame1 = await ws.readFrame()
check not isNil(frame1)
var data1 = newSeq[byte](frame1.remainder().int)
let read1 = await ws.stream.reader.readOnce(addr data1[0], data1.len)
check read1 == 5
let frame2 = await ws.readFrame()
check not isNil(frame2)
var data2 = newSeq[byte](frame2.remainder().int)
let read2 = await ws.stream.reader.readOnce(addr data2[0], data2.len)
check read2 == 5
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
frameSize = 5)
await wsClient.send(testString)
await wsClient.close()
test "should fail to read past max message size":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
let testString = "1234567890"
proc cb(r: RequestFence): Future[HttpResponseRef] {.async, gcsafe.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await ws.send(testString)
await ws.close()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
WIP: Implement websocket TLS. (#7) * Update http to use chronos http. * Implement TLS in websocket. * Add webscoket TLS test. * Minor nit. * Add TLS test file. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * merge master * wip * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Update http to use chronos http. * Implement TLS in websocket. * Minor nit. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * add testing keys * wip * fix test * wip * remove eth dep and add skipdirs * fix package structure * fix deps * check nim version * Fix CI failure. * Don't call `ws.stream.closeWait()` * always close both ends to complete the sequence * misc * don't fail on close * Fix windows CI. * fix linux x86 builds * use consistent connect pattern * move keys to better place * return dumbResponse * small cleanup Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com>
2021-04-13 22:05:58 +00:00
expect WSMaxMessageSizeError:
discard await wsClient.recv(5)
await waitForClose(wsClient)
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
suite "Test Closing":
teardown:
await server.closeWait()
test "Server closing":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await ws.close()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
WIP: Implement websocket TLS. (#7) * Update http to use chronos http. * Implement TLS in websocket. * Add webscoket TLS test. * Minor nit. * Add TLS test file. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * merge master * wip * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Update http to use chronos http. * Implement TLS in websocket. * Minor nit. * Update http to use chronos http. (#6) * Update http to use chronos http. * Add stream.nim file. * Address comments. * Fix CI failure. * Minor change. * Address comments. * Fix windows CI failing test. * minor cleanup * spacess * more idiomatic connect * use stew/base10 Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com> * Implement TLS in websocket. * Minor nit. * add testing keys * wip * fix test * wip * remove eth dep and add skipdirs * fix package structure * fix deps * check nim version * Fix CI failure. * Don't call `ws.stream.closeWait()` * always close both ends to complete the sequence * misc * don't fail on close * Fix windows CI. * fix linux x86 builds * use consistent connect pattern * move keys to better place * return dumbResponse * small cleanup Co-authored-by: Dmitriy Ryajov <dryajov@gmail.com>
2021-04-13 22:05:58 +00:00
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await waitForClose(wsClient)
check wsClient.readyState == ReadyState.Closed
test "Server closing with status":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
proc closeServer(status: Status, reason: string): CloseResult{.gcsafe,
raises: [Defect].} =
try:
check status == Status.TooLarge
check reason == "Message too big!"
except Exception as exc:
raise newException(Defect, exc.msg)
return (Status.Fulfilled, "")
let server = WSServer.new(
protos = ["proto"],
onClose = closeServer
)
let ws = await server.handleRequest(request)
await ws.close()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
proc clientClose(status: Status, reason: string): CloseResult {.gcsafe,
raises: [Defect].} =
try:
check status == Status.Fulfilled
return (Status.TooLarge, "Message too big!")
except Exception as exc:
raise newException(Defect, exc.msg)
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
onClose = clientClose)
await waitForClose(wsClient)
check wsClient.readyState == ReadyState.Closed
test "Client closing":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.close()
test "Client closing with status":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async, gcsafe.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
proc closeServer(status: Status, reason: string): CloseResult{.gcsafe,
raises: [Defect].} =
try:
check status == Status.Fulfilled
return (Status.TooLarge, "Message too big!")
except Exception as exc:
raise newException(Defect, exc.msg)
let server = WSServer.new(
protos = ["proto"],
onClose = closeServer
)
let ws = await server.handleRequest(request)
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
proc clientClose(status: Status, reason: string): CloseResult {.gcsafe,
raises: [Defect].} =
try:
check status == Status.TooLarge
check reason == "Message too big!"
return (Status.Fulfilled, "")
except Exception as exc:
raise newException(Defect, exc.msg)
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
onClose = clientClose)
await wsClient.close()
check wsClient.readyState == ReadyState.Closed
test "Server closing with valid close code 3999":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async, gcsafe.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await ws.close(code = Status.ReservedCode)
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
proc closeClient(status: Status, reason: string): CloseResult{.gcsafe,
raises: [Defect].} =
try:
check status == Status.ReservedCode
return (Status.ReservedCode, "Reserved Status")
except Exception as exc:
raise newException(Defect, exc.msg)
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
onClose = closeClient)
await waitForClose(wsClient)
test "Client closing with valid close code 3999":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async, gcsafe.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
proc closeServer(status: Status, reason: string): CloseResult{.gcsafe,
raises: [Defect].} =
try:
check status == Status.ReservedCode
return (Status.ReservedCode, "Reserved Status")
except Exception as exc:
raise newException(Defect, exc.msg)
let server = WSServer.new(
protos = ["proto"],
onClose = closeServer
)
let ws = await server.handleRequest(request)
await waitForClose(ws)
return dumbResponse()
let res = HttpServerRef.new(address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.close(code = Status.ReservedCode)
test "Server closing with Payload of length 2":
when defined(windows):
# TODO: fix this err on Windows
# Unhandled exception: Stream is already closed! [AsyncStreamIncorrectDefect]
skip()
else:
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
# Close with payload of length 2
await ws.close(reason = "HH")
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await waitForClose(wsClient)
test "Client closing with Payload of length 2":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
await waitForClose(ws)
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
# Close with payload of length 2
await wsClient.close(reason = "HH")
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
2021-05-22 09:04:40 +00:00
suite "Test Payload":
teardown:
await server.closeWait()
test "Test payload message length":
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
expect WSPayloadTooLarge:
discard await ws.recv()
await waitForClose(ws)
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let str = rndStr(126)
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
2021-05-22 09:04:40 +00:00
await wsClient.ping(str.toBytes())
await wsClient.close()
test "Test single empty payload":
let emptyStr = ""
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
check string.fromBytes(servRes) == emptyStr
await waitForClose(ws)
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.send(emptyStr)
await wsClient.close()
test "Test multiple empty payload":
let emptyStr = ""
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
check string.fromBytes(servRes) == emptyStr
await waitForClose(ws)
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
for i in 0..3:
await wsClient.send(emptyStr)
await wsClient.close()
test "Send ping with small text payload":
let testData = toBytes("Hello, world!")
var ping, pong = false
proc process(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
onPing = proc(data: openArray[byte]) =
ping = data == testData)
let ws = await server.handleRequest(request)
await waitForClose(ws)
let res = HttpServerRef.new(
address, process)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
)
await wsClient.ping(testData)
await wsClient.close()
check:
ping
pong
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false
2021-04-15 08:00:52 +00:00
suite "Test Binary message with Payload":
teardown:
await server.closeWait()
test "Test binary message with single empty payload message":
let emptyData = newSeq[byte](0)
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
2021-04-15 08:00:52 +00:00
check:
servRes == emptyData
2021-05-22 09:04:40 +00:00
ws.binary == true
2021-04-15 08:00:52 +00:00
await waitForClose(ws)
let res = HttpServerRef.new(address, cb)
2021-04-15 08:00:52 +00:00
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
await wsClient.send(emptyData, Opcode.Binary)
await wsClient.close()
test "Test binary message with multiple empty payload":
let emptyData = newSeq[byte](0)
proc cb(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(protos = ["proto"])
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let servRes = await ws.recv()
2021-04-15 08:00:52 +00:00
check:
servRes == emptyData
2021-05-22 09:04:40 +00:00
ws.binary == true
2021-04-15 08:00:52 +00:00
await waitForClose(ws)
let res = HttpServerRef.new(
address, cb)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"])
for i in 0..3:
await wsClient.send(emptyData, Opcode.Binary)
await wsClient.close()
test "Send binary data with small text payload":
let testData = rndBin(10)
debug "testData", testData = testData
var ping, pong = false
proc process(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
2021-05-22 09:04:40 +00:00
onPing = proc(data: openArray[byte]) =
ping = true
2021-04-15 08:00:52 +00:00
)
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let res = await ws.recv()
2021-04-15 08:00:52 +00:00
check:
res == testData
2021-05-22 09:04:40 +00:00
ws.binary == true
2021-04-15 08:00:52 +00:00
await waitForClose(ws)
let res = HttpServerRef.new(
address, process)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
2021-04-15 08:00:52 +00:00
)
await wsClient.send(testData, Opcode.Binary)
await wsClient.close()
test "Send binary message message with payload of length 125":
let testData = rndBin(125)
var ping, pong = false
proc process(r: RequestFence): Future[HttpResponseRef] {.async.} =
if r.isErr():
return dumbResponse()
2021-04-15 08:00:52 +00:00
let request = r.get()
check request.uri.path == "/ws"
let server = WSServer.new(
protos = ["proto"],
2021-05-22 09:04:40 +00:00
onPing = proc(data: openArray[byte]) =
ping = true
2021-04-15 08:00:52 +00:00
)
let ws = await server.handleRequest(request)
2021-05-22 09:04:40 +00:00
let res = await ws.recv()
2021-04-15 08:00:52 +00:00
check:
res == testData
2021-05-22 09:04:40 +00:00
ws.binary == true
2021-04-15 08:00:52 +00:00
await waitForClose(ws)
let res = HttpServerRef.new(
address, process)
server = res.get()
server.start()
let wsClient = await WebSocket.connect(
"127.0.0.1",
Port(8888),
path = "/ws",
protocols = @["proto"],
2021-05-22 09:04:40 +00:00
onPong = proc(data: openArray[byte]) =
pong = true
2021-04-15 08:00:52 +00:00
)
await wsClient.send(testData, Opcode.Binary)
await wsClient.close()
test "AsyncStream leaks test":
check:
getTracker("async.stream.reader").isLeaked() == false
getTracker("async.stream.writer").isLeaked() == false
getTracker("stream.server").isLeaked() == false
getTracker("stream.transport").isLeaked() == false