diff --git a/.github/workflows/ping-interop-latest.yml b/.github/workflows/ping-interop-latest.yml index 435e679a6..1f3c2348e 100644 --- a/.github/workflows/ping-interop-latest.yml +++ b/.github/workflows/ping-interop-latest.yml @@ -14,22 +14,22 @@ on: required: false type: string custom_interop_target: - description: in the case of cross-implementation testing, the implementation target (go | rust | ...) + description: in the case of cross-implementation testing, the implementation target (go | rust | nim) required: false type: string push: pull_request: -name: libp2p ping - go + rust test (latest) with testground. +name: libp2p ping - go, rust and nim test (latest) with testground. jobs: run-ping-latest: uses: "./.github/workflows/run-composition.yml" with: - composition_file: "ping/_compositions/go-rust-interop-latest.toml" + composition_file: "ping/_compositions/all-interop-latest.toml" custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p" custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference - custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust + custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim testground_endpoint: ${{ github.event.inputs.testground_endpoint }} test_repository: ${{ (github.event.inputs && '') || github.repository }} - test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }} \ No newline at end of file + test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/ping-interop.yml b/.github/workflows/ping-interop.yml index 8e2fa32ee..0f6b0fce6 100644 --- a/.github/workflows/ping-interop.yml +++ b/.github/workflows/ping-interop.yml @@ -14,32 +14,32 @@ on: required: false type: string custom_interop_target: - description: in the case of cross-implementation testing, the implementation target (go | rust | ...) + description: in the case of cross-implementation testing, the implementation target (go | rust | nim) required: false type: string push: pull_request: -name: libp2p ping - go and rust test (all) with testground. +name: libp2p ping - go, rust and nim test (all) with testground. jobs: run-ping-latest: uses: "./.github/workflows/run-composition.yml" with: - composition_file: "ping/_compositions/go-rust-interop-latest.toml" + composition_file: "ping/_compositions/all-interop-latest.toml" custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p" custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference - custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust + custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim testground_endpoint: ${{ github.event.inputs.testground_endpoint }} test_repository: ${{ (github.event.inputs && '') || github.repository }} test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }} run-ping-all: uses: "./.github/workflows/run-composition.yml" with: - composition_file: "ping/_compositions/go-rust-interop.toml" + composition_file: "ping/_compositions/all-interop.toml" custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p" custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference - custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust + custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim testground_endpoint: ${{ github.event.inputs.testground_endpoint }} test_repository: ${{ (github.event.inputs && '') || github.repository }} - test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }} \ No newline at end of file + test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }} diff --git a/ping/_compositions/go-rust-interop-latest.toml b/ping/_compositions/all-interop-latest.toml similarity index 74% rename from ping/_compositions/go-rust-interop-latest.toml rename to ping/_compositions/all-interop-latest.toml index a4c342581..2992c6b13 100644 --- a/ping/_compositions/go-rust-interop-latest.toml +++ b/ping/_compositions/all-interop-latest.toml @@ -1,5 +1,5 @@ [metadata] - name = "go-rust-cross-version-{{ or $.Env.InteropTarget "-" }}-{{ or $.Env.GitReference "" }}" + name = "all-latest-{{ or $.Env.InteropTarget "-" }}-{{ or $.Env.GitReference "" }}" [global] plan = "libp2p/ping" @@ -97,3 +97,35 @@ {{ end }} {{ end }} {{ end }} + +{{ with (load_resource "./nim.toml") }} + {{ with (index .groups 0) }} + [[groups]] + id = "nim-latest-{{ .Id }}" + instances = { count = 1 } + builder = "docker:generic" + + [groups.build_config] + path = "./nim/" + [groups.build_config.build_args] + Libp2pVersion = '{{ .Id }}' + NimVersion = '{{ .NimVersion }}' + {{ end }} + + {{ if eq $.Env.InteropTarget "nim" }} + {{ if $.Env.GitReference }} + {{ with .custom }} + [[groups]] + id = "nim-custom-{{ $.Env.GitReference }}" + instances = { count = 1 } + builder = "docker:generic" + + [groups.build_config] + path = "./nim/" + [groups.build_config.build_args] + Libp2pVersion = '#{{ $.Env.GitReference }}' + NimVersion = '{{ .NimVersion }}' + {{ end }} + {{ end }} + {{ end }} +{{ end }} diff --git a/ping/_compositions/go-rust-interop.toml b/ping/_compositions/all-interop.toml similarity index 75% rename from ping/_compositions/go-rust-interop.toml rename to ping/_compositions/all-interop.toml index a1df3bee4..9af35a242 100644 --- a/ping/_compositions/go-rust-interop.toml +++ b/ping/_compositions/all-interop.toml @@ -1,5 +1,5 @@ [metadata] - name = "go-rust-cross-version" + name = "all-cross-version" [global] plan = "libp2p/ping" @@ -138,3 +138,48 @@ {{ end }} {{ end }} {{ end }} + +{{ with (load_resource "./nim.toml") }} + {{ range .groups }} + [[groups]] + id = "nim-latest-{{ .Id }}" + instances = { count = 1 } + builder = "docker:generic" + + [groups.build_config] + path = "./nim/" + [groups.build_config.build_args] + Libp2pVersion = '{{ .Id }}' + NimVersion = '{{ .NimVersion }}' + {{ end }} + + {{ with .custom }} + [[groups]] + id = "nim-unstable" + instances = { count = 1 } + builder = "docker:generic" + + [groups.build_config] + path = "./nim/" + [groups.build_config.build_args] + Libp2pVersion = '#unstable' + NimVersion = '{{ .NimVersion }}' + {{ end }} + + {{ if eq $.Env.InteropTarget "nim" }} + {{ if $.Env.GitReference }} + {{ with .custom }} + [[groups]] + id = "nim-custom-{{ $.Env.GitReference }}" + instances = { count = 1 } + builder = "docker:generic" + + [groups.build_config] + path = "./nim/" + [groups.build_config.build_args] + Libp2pVersion = '#{{ $.Env.GitReference }}' + NimVersion = '{{ .NimVersion }}' + {{ end }} + {{ end }} + {{ end }} +{{ end }} diff --git a/ping/_compositions/nim.toml b/ping/_compositions/nim.toml new file mode 100644 index 000000000..8354f5b2f --- /dev/null +++ b/ping/_compositions/nim.toml @@ -0,0 +1,6 @@ +[custom] +NimVersion = "1.6.8" + +[[groups]] +Id = "1.0.0" +NimVersion = "1.6.8" diff --git a/ping/nim/Dockerfile b/ping/nim/Dockerfile new file mode 100644 index 000000000..afedf3c73 --- /dev/null +++ b/ping/nim/Dockerfile @@ -0,0 +1,14 @@ +ARG NimVersion="latest" +FROM nimlang/nim:${NimVersion}-alpine as builder + +RUN nimble install -y "https://github.com/status-im/testground-nim-sdk@#c282ff68c08ef85a7ca011e077e3e69eb1a6edec" + +ARG Libp2pVersion="#unstable" +RUN nimble install -y "libp2p@${Libp2pVersion}" +FROM builder + +ARG PLAN_PATH="./" +COPY ./plan/${PLAN_PATH} ./plan +RUN cd plan && nimble install -dy && nim c -d:chronicles_log_level=NOTICE main.nim + +ENTRYPOINT ["plan/main"] diff --git a/ping/nim/libp2p_ping.nimble b/ping/nim/libp2p_ping.nimble new file mode 100644 index 000000000..f75795abd --- /dev/null +++ b/ping/nim/libp2p_ping.nimble @@ -0,0 +1,13 @@ +# Package + +version = "0.1.0" +author = "The author" +description = "Demo for another package" +license = "MIT" + + +# Dependencies + +requires "nim >= 1.2.2", + "https://github.com/status-im/testground-nim-sdk", + "libp2p == 1.0.0" diff --git a/ping/nim/main.nim b/ping/nim/main.nim new file mode 100644 index 000000000..6c2ef5845 --- /dev/null +++ b/ping/nim/main.nim @@ -0,0 +1,93 @@ +import serialization, json_serialization +import libp2p, testground_sdk, libp2p/protocols/ping +import chronos +import sequtils + +type + PeerData = object + id {.serializedFieldName: "ID".}: string + addrs {.serializedFieldName: "Addrs".}: seq[string] + +testground(client): + let addresses = getInterfaces().filterIt(it.name == "eth1").mapIt(it.addresses) + if addresses.len < 1 or addresses[0].len < 1: + quit "Can't find local ip!" + + discard await client.signal("initialized_global") + + let + maxLatency = client.param(int, "max_latency_ms") + rng = libp2p.newRng() + address = addresses[0][0].host + switch = + SwitchBuilder + .new() + .withAddress(MultiAddress.init(address).tryGet()) + .withRng(rng) + .withYamux() + .withTcpTransport() + .withNoise() + .build() + pingProtocol = Ping.new(rng = rng) + + switch.mount(pingProtocol) + await switch.start() + defer: await switch.stop() + + let peersTopic = client.subscribe("peers", PeerData) + await client.publish("peers", + PeerData( + id: $switch.peerInfo.peerId, + addrs: switch.peerInfo.addrs.mapIt($it) + ) + ) + echo "Listening on ", switch.peerInfo.addrs + + var peersInfo: seq[PeerData] + while peersInfo.len < client.testInstanceCount: + peersInfo.add(await peersTopic.popFirst()) + + for peerInfo in peersInfo: + if peerInfo.id == $switch.peerInfo.peerId: break + let + peerId = PeerId.init(peerInfo.id).tryGet() + addrs = peerInfo.addrs.mapIt(MultiAddress.init(it).tryGet()) + await switch.connect(peerId, addrs) + + discard await client.signalAndWait("connected", client.testInstanceCount) + + proc pingPeer(peer: PeerData, tag: string) {.async.} = + if peer.id == $switch.peerInfo.peerId: return + let + stream = await switch.dial(PeerId.init(peer.id).tryGet(), PingCodec) + rtt = await pingProtocol.ping(stream) + await stream.close() + client.recordMessage("ping result (" & tag & ") from peer " & peer.id & ": " & $rtt) + + var futs: seq[Future[void]] + for peer in peersInfo: futs.add(pingPeer(peer, "initial")) + await allFutures(futs) + + discard await client.signalAndWait("initial", client.testInstanceCount) + + for iter in 1 .. client.param(int, "iterations"): + let + latency = milliseconds(rng.rand(maxLatency)) + callbackState = "network-configured-" & $iter + client.recordMessage("Iteration " & $iter & ", my latency: " & $latency) + await client.updateNetworkParameter( + NetworkConf( + enable: true, + network: "default", + callback_state: callbackState, + callback_target: some client.testInstanceCount, + routing_policy: "accept_all", + default: LinkShape(latency: int(latency.nanoseconds)) + ) + ) + await client.waitForBarrier(callbackState, client.testInstanceCount) + + for peer in peersInfo: futs.add(pingPeer(peer, "iteration-" & $iter)) + await allFutures(futs) + + discard await client.signalAndWait("done-" & $iter, client.testInstanceCount) diff --git a/ping/nim/manifest.toml b/ping/nim/manifest.toml new file mode 100644 index 000000000..62a4640f1 --- /dev/null +++ b/ping/nim/manifest.toml @@ -0,0 +1,19 @@ +name = "compatibility-nim" + +[defaults] +builder = "docker:generic" +runner = "local:docker" + +[builders."docker:generic"] +enabled = true + +[runners."local:docker"] +enabled = true + +[[testcases]] +name = "ping" +instances = { min = 2, max = 10000, default = 5 } + + [testcases.params] + max_latency_ms = { type = "int", desc = "maximum value for random local link latency", unit = "ms", default = 1000 } + iterations = { type = "int", desc = "number of ping iterations we'll run against each peer", unit = "count", default = 5 }