Cleanup utp_test and make the code more flexible to change amounts (#1972)
This commit is contained in:
parent
fb2aa1b6f9
commit
2df9e2b7b1
|
@ -1,9 +1,9 @@
|
|||
# uTP testing infrastructure
|
||||
# uTP testing infrastructure
|
||||
|
||||
Testing infrastructure which enables to test uTP implementation over different
|
||||
network conditions on local machine.
|
||||
network conditions on a local machine.
|
||||
|
||||
Highly based on tools developed to test quic protocol:
|
||||
Uses following tools developed to test the QUIC protocol:
|
||||
|
||||
[quic-interop-runner](https://github.com/marten-seemann/quic-interop-runner)
|
||||
|
||||
|
@ -11,19 +11,20 @@ Highly based on tools developed to test quic protocol:
|
|||
|
||||
## Prerequisities
|
||||
|
||||
- Machine with docker installed
|
||||
- Machine with Docker installed
|
||||
|
||||
- nimbus-eth1 set-up to run `make utp_test`
|
||||
|
||||
## How it works
|
||||
|
||||
Test setup uses docker compose to start 3 docker containers:
|
||||
- client - which is instance of uTP test app
|
||||
- server - which is instance of uTP test app
|
||||
- sim - which is instance with ns3 network simulator with several pre-compiled scenarios
|
||||
Test setup uses Docker Compose to start 3 Docker containers:
|
||||
- uTP client - which is an instance of the `utp_test_app`
|
||||
- uTP server - which is an instance of the `utp_test_app`
|
||||
- sim - which is an instance of the ns3 network simulator with several pre-compiled scenarios
|
||||
|
||||
The networking is setup in such way that network traffic is routed from client to server
|
||||
and server to client thorugh sim which decideds what to do with flowing packets
|
||||
The networking is set up in such way that network traffic is routed from client to server
|
||||
and server to client through the simulator.
|
||||
The simulator decides what to do with packets passing through based on the selected scneario.
|
||||
|
||||
Explanation from [quic-network-simulator](https://github.com/marten-seemann/quic-network-simulator):
|
||||
|
||||
|
@ -38,9 +39,9 @@ simulation sits in the middle and forwards packets between `leftnet` and
|
|||
|
||||
## Practicalities
|
||||
|
||||
For now process is semi-manual (TODO automate this as much as possible)
|
||||
For now the process is semi-manual (TODO automate this as much as possible)
|
||||
|
||||
To run integration testing scenarios with different network conditions
|
||||
To run integration testing scenarios with different network conditions:
|
||||
|
||||
```
|
||||
1. cd nimbus-eth1/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
version: "3.5"
|
||||
|
||||
# TODO Add possibility to configure ports by env vcariables
|
||||
# TODO Add possibility to configure ports by env variables
|
||||
services:
|
||||
sim:
|
||||
# TODO for now we are using simulator which is also used in quic, ultimatly
|
||||
|
@ -14,7 +14,7 @@ services:
|
|||
- ./logs/sim:/logs
|
||||
environment:
|
||||
- SCENARIO=$SCENARIO
|
||||
cap_add:
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
expose:
|
||||
- "57832"
|
||||
|
@ -30,8 +30,6 @@ services:
|
|||
# TODO add building of docker images based on variable
|
||||
# build: ./$SERVER
|
||||
image: test-utp
|
||||
# this arg will go to container entry point
|
||||
command: "--udp-listen-address=193.167.100.100 --rpc-listen-address=0.0.0.0 --udp-port=9041 --rpc-port=9041"
|
||||
container_name: server
|
||||
hostname: server
|
||||
stdin_open: true
|
||||
|
@ -43,7 +41,7 @@ services:
|
|||
- CLIENT_PARAMS=--udp-listen-address=193.167.100.100 --rpc-listen-address=0.0.0.0 --udp-port=9041 --rpc-port=9041
|
||||
depends_on:
|
||||
- sim
|
||||
cap_add:
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
ports:
|
||||
- "9041:9041"
|
||||
|
@ -60,7 +58,6 @@ services:
|
|||
client:
|
||||
# build: ./$CLIENT
|
||||
image: test-utp
|
||||
command: "--udp-listen-address=193.167.0.100 --rpc-listen-address=0.0.0.0 --udp-port=9042 --rpc-port=9042"
|
||||
container_name: client
|
||||
hostname: client
|
||||
stdin_open: true
|
||||
|
@ -72,7 +69,7 @@ services:
|
|||
- CLIENT_PARAMS=--udp-listen-address=193.167.0.100 --rpc-listen-address=0.0.0.0 --udp-port=9042 --rpc-port=9042
|
||||
depends_on:
|
||||
- sim
|
||||
cap_add:
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
ports:
|
||||
- "9042:9042"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Nimbus
|
||||
# Copyright (c) 2022-2023 Status Research & Development GmbH
|
||||
# Fluffy
|
||||
# Copyright (c) 2022-2024 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
@ -10,13 +10,13 @@ import
|
|||
unittest2, testutils, chronos,
|
||||
json_rpc/rpcclient, stew/byteutils,
|
||||
eth/keys,
|
||||
./utp_test_client
|
||||
./utp_test_rpc_client
|
||||
|
||||
proc generateBytesHex(rng: var HmacDrbgContext, length: int): string =
|
||||
rng.generateBytes(length).toHex()
|
||||
|
||||
# Before running the test suite, there need to be two instances of the
|
||||
# utp_test_app running under provided ports (9042, 9041).
|
||||
# Before running this test suite, there need to be two instances of the
|
||||
# utp_test_app running under the tested ports: 9042, 9041.
|
||||
# Those could be launched locally by running either
|
||||
# ./utp_test_app --udp-listen-address=127.0.0.1 --rpc-listen-address=0.0.0.0 --udp-port=9041 --rpc-port=9041
|
||||
# ./utp_test_app --udp-listen-address=127.0.0.1 --rpc-listen-address=0.0.0.0 --udp-port=9042 --rpc-port=9042
|
||||
|
@ -24,13 +24,15 @@ proc generateBytesHex(rng: var HmacDrbgContext, length: int): string =
|
|||
# running from docker dir:
|
||||
# 1. docker build -t test-utp --no-cache --build-arg BRANCH_NAME=branch-name .
|
||||
# 2. SCENARIO="scenario name and params " docker-compose up
|
||||
procSuite "uTP integration tests":
|
||||
let rng = newRng()
|
||||
let clientContainerAddress = "127.0.0.1"
|
||||
let clientContainerPort = Port(9042)
|
||||
|
||||
let serverContainerAddress = "127.0.0.1"
|
||||
let serverContainerPort = Port(9041)
|
||||
procSuite "uTP network simulator tests":
|
||||
const
|
||||
clientContainerAddress = "127.0.0.1"
|
||||
clientContainerPort = Port(9042)
|
||||
serverContainerAddress = "127.0.0.1"
|
||||
serverContainerPort = Port(9041)
|
||||
|
||||
let rng = newRng()
|
||||
|
||||
type
|
||||
FutureCallback[A] = proc (): Future[A] {.gcsafe, raises: [].}
|
||||
|
@ -56,9 +58,9 @@ procSuite "uTP integration tests":
|
|||
raise canc
|
||||
|
||||
proc findServerConnection(
|
||||
connections: openArray[SKey],
|
||||
clientId: NodeId,
|
||||
clientConnectionId: uint16): Option[Skey] =
|
||||
connections: openArray[SKey],
|
||||
clientId: NodeId,
|
||||
clientConnectionId: uint16): Option[Skey] =
|
||||
let conns: seq[SKey] =
|
||||
connections.filter((key:Skey) => key.id == (clientConnectionId + 1) and
|
||||
key.nodeId == clientId)
|
||||
|
@ -75,20 +77,20 @@ procSuite "uTP integration tests":
|
|||
await client.connect(clientContainerAddress, clientContainerPort, false)
|
||||
await server.connect(serverContainerAddress, serverContainerPort, false)
|
||||
|
||||
# we may need to retry few times if the simm is not ready yet
|
||||
# we may need to retry few times if the sim is not ready yet
|
||||
let clientInfo = await repeatTillSuccess(() => client.discv5_nodeInfo(), 10)
|
||||
|
||||
let serverInfo = await repeatTillSuccess(() => server.discv5_nodeInfo(), 10)
|
||||
|
||||
# nodes need to have established session before the utp try
|
||||
# nodes need to have an established discv5 session before the uTP test
|
||||
discard await repeatTillSuccess(() => client.discv5_ping(serverInfo.enr))
|
||||
|
||||
return (client, clientInfo, server, serverInfo)
|
||||
|
||||
asyncTest "Transfer 100k bytes of data over utp stream from client to server":
|
||||
let (client, clientInfo, server, serverInfo) = await setupTest()
|
||||
let numOfBytes = 100000
|
||||
asyncTest "100kb transfer from client to server":
|
||||
const amountOfBytes = 100_000
|
||||
|
||||
let
|
||||
(client, clientInfo, server, serverInfo) = await setupTest()
|
||||
clientConnectionKey = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
serverConnections = await repeatTillSuccess(() =>
|
||||
|
@ -99,24 +101,24 @@ procSuite "uTP integration tests":
|
|||
check:
|
||||
maybeServerConnectionKey.isSome()
|
||||
|
||||
let serverConnectionKey = maybeServerConnectionKey.unsafeGet()
|
||||
|
||||
let
|
||||
bytesToWrite = generateBytesHex(rng[], numOfBytes)
|
||||
serverConnectionKey = maybeServerConnectionKey.unsafeGet()
|
||||
bytesToWrite = generateBytesHex(rng[], amountOfBytes)
|
||||
writeRes = await client.utp_write(clientConnectionKey, bytesToWrite)
|
||||
readData = await server.utp_read(serverConnectionKey, numOfBytes)
|
||||
dataRead = await server.utp_read(serverConnectionKey, amountOfBytes)
|
||||
|
||||
check:
|
||||
writeRes == true
|
||||
readData == bytesToWrite
|
||||
dataRead == bytesToWrite
|
||||
|
||||
asyncTest "Transfer 100k bytes of data over utp stream from server to client":
|
||||
asyncTest "100kb transfer from server to client":
|
||||
# In classic uTP this would not be possible, as when uTP works over UDP the
|
||||
# client needs to transfer first, but when working over discv5 it should be
|
||||
# possible to transfer data from server to client from the start.
|
||||
let (client, clientInfo, server, serverInfo) = await setupTest()
|
||||
let numOfBytes = 100000
|
||||
const amountOfBytes = 100_000
|
||||
|
||||
let
|
||||
(client, clientInfo, server, serverInfo) = await setupTest()
|
||||
clientConnectionKey = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
serverConnections = await repeatTillSuccess(() =>
|
||||
|
@ -127,21 +129,23 @@ procSuite "uTP integration tests":
|
|||
check:
|
||||
maybeServerConnectionKey.isSome()
|
||||
|
||||
let serverConnectionKey = maybeServerConnectionKey.unsafeGet()
|
||||
|
||||
let
|
||||
bytesToWrite = generateBytesHex(rng[], numOfBytes)
|
||||
serverConnectionKey = maybeServerConnectionKey.unsafeGet()
|
||||
bytesToWrite = generateBytesHex(rng[], amountOfBytes)
|
||||
writeRes = await server.utp_write(serverConnectionKey, bytesToWrite)
|
||||
readData = await client.utp_read(clientConnectionKey, numOfBytes)
|
||||
dataRead = await client.utp_read(clientConnectionKey, amountOfBytes)
|
||||
|
||||
check:
|
||||
writeRes == true
|
||||
readData == bytesToWrite
|
||||
dataRead == bytesToWrite
|
||||
|
||||
asyncTest "Multiple 10kb transfers from client to server":
|
||||
const
|
||||
amountOfBytes = 10_000
|
||||
amountOfTransfers = 3
|
||||
|
||||
asyncTest "Multiple 10k bytes transfers over utp stream":
|
||||
let (client, clientInfo, server, serverInfo) = await setupTest()
|
||||
let numOfBytes = 10000
|
||||
let
|
||||
(client, clientInfo, server, serverInfo) = await setupTest()
|
||||
clientConnectionKey = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
serverConnections = await repeatTillSuccess(() =>
|
||||
|
@ -154,71 +158,47 @@ procSuite "uTP integration tests":
|
|||
|
||||
let serverConnectionKey = maybeServerConnectionKey.unsafeGet()
|
||||
|
||||
let
|
||||
bytesToWrite = generateBytesHex(rng[], numOfBytes)
|
||||
bytesToWrite1 = generateBytesHex(rng[], numOfBytes)
|
||||
bytesToWrite2 = generateBytesHex(rng[], numOfBytes)
|
||||
writeRes = await client.utp_write(clientConnectionKey, bytesToWrite)
|
||||
writeRes1 = await client.utp_write(clientConnectionKey, bytesToWrite1)
|
||||
writeRes2 = await client.utp_write(clientConnectionKey, bytesToWrite2)
|
||||
readData = await server.utp_read(serverConnectionKey, numOfBytes * 3)
|
||||
var totalBytesToWrite: string
|
||||
for i in 0..<amountOfTransfers:
|
||||
let
|
||||
bytesToWrite = generateBytesHex(rng[], amountOfBytes)
|
||||
writeRes = await client.utp_write(clientConnectionKey, bytesToWrite)
|
||||
|
||||
let writtenData = join(@[bytesToWrite, bytesToWrite1, bytesToWrite2])
|
||||
check writeRes == true
|
||||
totalBytesToWrite.add(bytesToWrite)
|
||||
|
||||
check:
|
||||
writeRes == true
|
||||
writeRes1 == true
|
||||
writeRes2 == true
|
||||
readData == writtenData
|
||||
let dataRead = await server.utp_read(
|
||||
serverConnectionKey, amountOfBytes * amountOfTransfers)
|
||||
|
||||
check dataRead == totalBytesToWrite
|
||||
|
||||
asyncTest "Multiple 10kb transfers over multiple sockets from client to server":
|
||||
const
|
||||
amountOfBytes = 10_000
|
||||
amountOfSockets = 3
|
||||
|
||||
asyncTest "Handle mulitplie sockets over one utp server instance ":
|
||||
let (client, clientInfo, server, serverInfo) = await setupTest()
|
||||
let numOfBytes = 10000
|
||||
let
|
||||
clientConnectionKey1 = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
clientConnectionKey2 = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
clientConnectionKey3 = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
serverConnections = await repeatTillSuccess(() =>
|
||||
server.utp_get_connections())
|
||||
|
||||
maybeServerConnectionKey1 = serverConnections.findServerConnection(
|
||||
clientInfo.nodeId, clientConnectionKey1.id)
|
||||
maybeServerConnectionKey2 = serverConnections.findServerConnection(
|
||||
clientInfo.nodeId, clientConnectionKey2.id)
|
||||
maybeServerConnectionKey3 = serverConnections.findServerConnection(
|
||||
clientInfo.nodeId, clientConnectionKey3.id)
|
||||
var connectionKeys: seq[(SKey, SKey)]
|
||||
for i in 0..<amountOfSockets:
|
||||
let
|
||||
clientConnectionKey = await repeatTillSuccess(() =>
|
||||
client.utp_connect(serverInfo.enr))
|
||||
serverConnections = await repeatTillSuccess(() =>
|
||||
server.utp_get_connections())
|
||||
serverConnectionKeyRes = serverConnections.findServerConnection(
|
||||
clientInfo.nodeId, clientConnectionKey.id)
|
||||
|
||||
check:
|
||||
maybeServerConnectionKey1.isSome()
|
||||
maybeServerConnectionKey2.isSome()
|
||||
maybeServerConnectionKey3.isSome()
|
||||
check serverConnectionKeyRes.isSome()
|
||||
|
||||
let serverConnectionKey1 = maybeServerConnectionKey1.unsafeGet()
|
||||
let serverConnectionKey2 = maybeServerConnectionKey2.unsafeGet()
|
||||
let serverConnectionKey3 = maybeServerConnectionKey3.unsafeGet()
|
||||
connectionKeys.add((clientConnectionKey, serverConnectionKeyRes.unsafeGet()))
|
||||
|
||||
let
|
||||
bytesToWrite1 = generateBytesHex(rng[], numOfBytes)
|
||||
bytesToWrite2 = generateBytesHex(rng[], numOfBytes)
|
||||
bytesToWrite3 = generateBytesHex(rng[], numOfBytes)
|
||||
for (clientConnectionKey, serverConnectionKey) in connectionKeys:
|
||||
let
|
||||
bytesToWrite = generateBytesHex(rng[], amountOfBytes)
|
||||
writeRes = await client.utp_write(clientConnectionKey, bytesToWrite)
|
||||
dataRead = await server.utp_read(serverConnectionKey, amountOfBytes)
|
||||
|
||||
writeRes1 = await client.utp_write(clientConnectionKey1, bytesToWrite1)
|
||||
writeRes2 = await client.utp_write(clientConnectionKey2, bytesToWrite2)
|
||||
writeRes3 = await client.utp_write(clientConnectionKey3, bytesToWrite3)
|
||||
|
||||
readData1 = await server.utp_read(serverConnectionKey1, numOfBytes)
|
||||
readData2 = await server.utp_read(serverConnectionKey2, numOfBytes)
|
||||
readData3 = await server.utp_read(serverConnectionKey3, numOfBytes)
|
||||
|
||||
check:
|
||||
writeRes1 == true
|
||||
writeRes2 == true
|
||||
writeRes3 == true
|
||||
|
||||
# all data was delivered to correct sockets
|
||||
readData1 == bytesToWrite1
|
||||
readData2 == bytesToWrite2
|
||||
readData3 == bytesToWrite3
|
||||
check:
|
||||
writeRes == true
|
||||
dataRead == bytesToWrite
|
||||
|
|
Loading…
Reference in New Issue