Skip to content

Commit e0effe4

Browse files
committed
fix: tests/helpers
1 parent c4eb388 commit e0effe4

13 files changed

Lines changed: 234 additions & 2 deletions

libs/lsquic

tests/helpers/addresses.nim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import pkg/chronos
2+
3+
const zeroAddress* = initTAddress("0.0.0.0:0")

tests/helpers/async.nim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pkg/chronos
2+
3+
type WaitGroup* = ref object of RootObj
4+
## A synchronization primitive that waits for a collection of
5+
## asynchronous tasks to finish.
6+
count: int
7+
fut: Future[void]
8+
9+
proc newWaitGroup*(count: int): WaitGroup =
10+
doAssert(count >= 0, "WaitGroup count must be non negative number")
11+
let fut = newFuture[void]("WaitGroup")
12+
if count == 0:
13+
fut.complete()
14+
WaitGroup(count: count, fut: fut)
15+
16+
proc wait*(wg: WaitGroup): Future[void] =
17+
wg.fut
18+
19+
proc done*(wg: WaitGroup) =
20+
if wg.count == 0:
21+
return
22+
23+
wg.count.dec
24+
if wg.count == 0 and not wg.fut.finished:
25+
wg.fut.complete()

tests/helpers/certificate.nim

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import sequtils
2+
import os
3+
4+
const certificateStr =
5+
staticRead(parentDir(currentSourcePath()) / "testCertificate.pem")
6+
const privateKeyStr = staticRead(parentDir(currentSourcePath()) / "testPrivateKey.pem")
7+
8+
proc strToSeq(val: string): seq[byte] =
9+
toSeq(val.toOpenArrayByte(0, val.high))
10+
11+
proc testCertificate*(): seq[byte] =
12+
strToSeq(certificateStr)
13+
14+
proc testPrivateKey*(): seq[byte] =
15+
strToSeq(privateKeyStr)

tests/helpers/clientserver.nim

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import results
2+
import pkg/quic
3+
import ./certificate
4+
5+
proc certificateCb(
6+
serverName: string, derCertificates: seq[seq[byte]]
7+
): bool {.gcsafe.} =
8+
return derCertificates.len > 0
9+
10+
proc makeClient*(): QuicClient =
11+
let customCertVerif: CertificateVerifier =
12+
CustomCertificateVerifier.init(certificateCb)
13+
let alpn = @["test"]
14+
let tlsConfig = TLSConfig.init(
15+
testCertificate(),
16+
testPrivateKey(),
17+
alpn,
18+
certificateVerifier = Opt.some(customCertVerif),
19+
)
20+
return QuicClient.init(tlsConfig)
21+
22+
proc makeServer*(): QuicServer =
23+
let customCertVerif: CertificateVerifier =
24+
CustomCertificateVerifier.init(certificateCb)
25+
let alpn = @["test"]
26+
let tlsConfig =
27+
TLSConfig.init(testCertificate(), testPrivateKey(), alpn, Opt.some(customCertVerif))
28+
return QuicServer.init(tlsConfig)

tests/helpers/contains.nim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
proc contains*(a: seq[byte], sub: seq[byte]): bool =
2+
for i in 0 ..< a.len - sub.len:
3+
if a[i ..< i + sub.len] == sub:
4+
return true

tests/helpers/nim.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--path:"../.."

tests/helpers/simulation.nim

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import std/[random, sets]
2+
import chronos
3+
import quic/transport/[quicconnection, quicclientserver, tlsbackend]
4+
import quic/helpers/[asyncloop, rand]
5+
import ./certificate
6+
import ./addresses
7+
8+
proc networkLoop*(source, destination: QuicConnectionection) {.async.} =
9+
proc transfer() {.async: (raises: [CancelledError]).} =
10+
let datagram = await source.outgoing.get()
11+
try:
12+
destination.receive(datagram)
13+
except CatchableError as e:
14+
# this is used in tests so it's fine to raise defect
15+
raise newException(Defect, e.msg)
16+
17+
await asyncLoop(transfer)
18+
19+
proc simulateNetwork*(a, b: QuicConnectionection) {.async.} =
20+
let loop1 = networkLoop(a, b)
21+
let loop2 = networkLoop(b, a)
22+
try:
23+
await allFutures(loop1, loop2)
24+
except CancelledError:
25+
await allFutures(loop1.cancelAndWait(), loop2.cancelAndWait())
26+
27+
proc lossyNetworkLoop*(source, destination: QuicConnectionection) {.async.} =
28+
proc transfer() {.async: (raises: [CancelledError]).} =
29+
let datagram = await source.outgoing.get()
30+
if rand(1.0) < 0.2:
31+
try:
32+
destination.receive(datagram)
33+
except CatchableError as e:
34+
# this is used in tests so it's fine to raise defect
35+
raise newException(Defect, e.msg)
36+
37+
await asyncLoop(transfer)
38+
39+
proc simulateLossyNetwork*(a, b: QuicConnectionection) {.async.} =
40+
let loop1 = lossyNetworkLoop(a, b)
41+
let loop2 = lossyNetworkLoop(b, a)
42+
try:
43+
await allFutures(loop1, loop2)
44+
except CancelledError:
45+
await allFutures(loop1.cancelAndWait(), loop2.cancelAndWait())
46+
47+
proc setupConnection*(): Future[tuple[client, server: QuicConnectionection]] {.async.} =
48+
let rng = newRng()
49+
let clientTLSBackend =
50+
newClientTLSBackend(@[], @[], toHashSet(@["test"]), Opt.none(CertificateVerifier))
51+
let client = newQuicClientConnection(clientTLSBackend, zeroAddress, zeroAddress, rng)
52+
53+
client.send() # Start Handshake
54+
let datagram = await client.outgoing.get()
55+
let serverTLSBackend = newServerTLSBackend(
56+
testCertificate(),
57+
testPrivateKey(),
58+
toHashSet(@["test"]),
59+
Opt.none(CertificateVerifier),
60+
)
61+
let server =
62+
newQuicServerConnection(serverTLSBackend, zeroAddress, zeroAddress, datagram, rng)
63+
64+
result = (client, server)
65+
66+
proc performHandshake*(): Future[tuple[client, server: QuicConnectionection]] {.async.} =
67+
let (client, server) = await setupConnection()
68+
let clientLoop = networkLoop(client, server)
69+
let serverLoop = networkLoop(server, client)
70+
await allFutures(client.handshake.wait(), server.handshake.wait())
71+
await serverLoop.cancelAndWait()
72+
await clientLoop.cancelAndWait()
73+
result = (client, server)

tests/helpers/stream.nim

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import pkg/chronos
2+
import pkg/unittest2
3+
import pkg/quic/transport/stream
4+
5+
proc newData*(size: int, val: uint8 = uint8(0xEE)): seq[uint8] =
6+
var data = newSeq[uint8](size)
7+
for i in 0 ..< size:
8+
data[i] = val
9+
return data
10+
11+
proc readStreamTillEOF*(
12+
stream: Stream, maxBytes: int = int.high
13+
): Future[seq[uint8]] {.async.} =
14+
## Reads from stream until EOF is reached or the received data size meets/exceeds maxBytes
15+
16+
var receivedData: seq[uint8]
17+
while true:
18+
let chunk = await stream.read()
19+
if chunk.len == 0:
20+
break
21+
receivedData.add(chunk)
22+
if receivedData.len >= maxBytes:
23+
break
24+
return receivedData
25+
26+
proc checkEqual*(a: seq[byte], b: seq[byte]) =
27+
if a.len != b.len:
28+
checkpoint("sequences do not have the same length: " & $a.len & " != " & $b.len)
29+
fail()
30+
return
31+
32+
for i in 0 ..< a.len:
33+
if a[i] != b[i]:
34+
checkpoint("sequences do not have same data")
35+
fail()
36+
return

tests/helpers/testCertificate.pem

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIB0jCCAXegAwIBAgIVAJUFhCQrlzzkFZbZkyXNRwCXSvYWMAwGCCqGSM49BAMC
3+
BQAwFDESMBAGA1UEAwwJbGlicDJwLmlvMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYw
4+
MTAxMDAwMDAwWjAUMRIwEAYDVQQDDAlsaWJwMnAuaW8wWTATBgcqhkjOPQIBBggq
5+
hkjOPQMBBwNCAAThQpOzDszrSDCf9wqR1+0WOt6BHVwv3Q3R+8quylRwLbR2D8ov
6+
PoXfWCzoACju9j2wBj4WHgb69Cpp9FiW7qx0o4GhMIGeMIGABgorBgEEAYOiWgEB
7+
BHIwbwQlCAISIQIz55rVQB21ks44HQ9G/0YJgvDB5v5/6Bl+MkQq5k3A4gRGMEQC
8+
IBLxYkAwI5H5GMzWPpjhOt3pJQ9gi7ICqCejEIFSuvf1AiA2kZZ+twfvyIYV7AAv
9+
InM3WOWZlgY4a7TDRm8C974pHwAwCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMCBaAw
10+
DAYIKoZIzj0EAwIFAANHADBEAiBV/KbtQ5SIAu373/8j/PzLnewCHUzXWTd3zjN9
11+
nzkGIgIgd1IJKDqnotzvCKw4WYrAmgTMkINJwlaQf278ranRaEY=
12+
-----END CERTIFICATE-----

0 commit comments

Comments
 (0)