diff --git a/.github/workflows/interop.yml b/.github/workflows/interop.yml index 70db62283..0f521894b 100644 --- a/.github/workflows/interop.yml +++ b/.github/workflows/interop.yml @@ -11,47 +11,19 @@ concurrency: cancel-in-progress: true jobs: - run-multidim-interop: - name: Run multidimensional interoperability tests + run-transport-interop: + name: Run transport interoperability tests runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 - with: - repository: libp2p/test-plans - submodules: true - fetch-depth: 0 - + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 - name: Build image - run: > - cd transport-interop/impl/nim/v1.0 && - make commitSha=$GITHUB_SHA image_name=nim-libp2p-head - - - name: Create ping-version.json - run: > - (cat << EOF - { - "id": "nim-libp2p-head", - "containerImageID": "nim-libp2p-head", - "transports": [ - "tcp", - "ws" - ], - "secureChannels": [ - "noise" - ], - "muxers": [ - "mplex", - "yamux" - ] - } - EOF - - ) > ${{ github.workspace }}/test_head.json - - - uses: libp2p/test-plans/.github/actions/run-transport-interop-test@master + run: docker buildx build --load -t nim-libp2p-head -f tests/transport-interop/Dockerfile . + - name: Run tests + uses: libp2p/test-plans/.github/actions/run-transport-interop-test@master with: test-filter: nim-libp2p-head - extra-versions: ${{ github.workspace }}/test_head.json + extra-versions: ${{ github.workspace }}/tests/transport-interop/version.json run-hole-punching-interop: name: Run hole-punching interoperability tests diff --git a/tests/transport-interop/Dockerfile b/tests/transport-interop/Dockerfile new file mode 100644 index 000000000..7276b426a --- /dev/null +++ b/tests/transport-interop/Dockerfile @@ -0,0 +1,16 @@ +# syntax=docker/dockerfile:1.5-labs +FROM nimlang/nim:1.6.16 as builder + +WORKDIR /app + +COPY .pinned libp2p.nimble nim-libp2p/ + +RUN cd nim-libp2p && nimble install_pinned && nimble install "redis@#b341fe240dbf11c544011dd0e033d3c3acca56af" -y + +COPY . nim-libp2p/ + +RUN \ + cd nim-libp2p && \ + nim c --skipProjCfg --skipParentCfg --NimblePath:./nimbledeps/pkgs -p:nim-libp2p -d:chronicles_log_level=WARN --threads:off ./tests/transport-interop/main.nim + +ENTRYPOINT ["/app/nim-libp2p/tests/transport-interop/main"] diff --git a/tests/transport-interop/main.nim b/tests/transport-interop/main.nim new file mode 100644 index 000000000..be37feb06 --- /dev/null +++ b/tests/transport-interop/main.nim @@ -0,0 +1,92 @@ +import + std/[os, strutils, sequtils], + chronos, redis, serialization, json_serialization +import ../../libp2p/[builders, protocols/ping, transports/wstransport] + +type + ResultJson = object + handshakePlusOneRTTMillis: float + pingRTTMilllis: float + +let + testTimeout = + try: seconds(parseInt(getEnv("test_timeout_seconds"))) + except CatchableError: 3.minutes + +proc main {.async.} = + + let + transport = getEnv("transport") + muxer = getEnv("muxer") + secureChannel = getEnv("security") + isDialer = getEnv("is_dialer") == "true" + envIp = getEnv("ip", "0.0.0.0") + ip = + # nim-libp2p doesn't do snazzy ip expansion + if envIp == "0.0.0.0": + block: + let addresses = getInterfaces().filterIt(it.name == "eth0").mapIt(it.addresses) + if addresses.len < 1 or addresses[0].len < 1: + quit "Can't find local ip!" + ($addresses[0][0].host).split(":")[0] + else: + envIp + redisAddr = getEnv("redis_addr", "redis:6379").split(":") + + # using synchronous redis because async redis is based on + # asyncdispatch instead of chronos + redisClient = open(redisAddr[0], Port(parseInt(redisAddr[1]))) + + switchBuilder = SwitchBuilder.new() + + case transport: + of "tcp": + discard switchBuilder.withTcpTransport().withAddress( + MultiAddress.init("/ip4/" & ip & "/tcp/0").tryGet() + ) + of "ws": + discard switchBuilder.withTransport(proc (upgr: Upgrade): Transport = WsTransport.new(upgr)).withAddress( + MultiAddress.init("/ip4/" & ip & "/tcp/0/ws").tryGet() + ) + else: doAssert false + + case secureChannel: + of "noise": discard switchBuilder.withNoise() + else: doAssert false + + case muxer: + of "yamux": discard switchBuilder.withYamux() + of "mplex": discard switchBuilder.withMplex() + else: doAssert false + + let + rng = newRng() + switch = switchBuilder.withRng(rng).build() + pingProtocol = Ping.new(rng = rng) + switch.mount(pingProtocol) + await switch.start() + defer: await switch.stop() + + if not isDialer: + discard redisClient.rPush("listenerAddr", $switch.peerInfo.fullAddrs.tryGet()[0]) + await sleepAsync(100.hours) # will get cancelled + else: + let + remoteAddr = MultiAddress.init(redisClient.bLPop(@["listenerAddr"], testTimeout.seconds.int)[1]).tryGet() + dialingStart = Moment.now() + remotePeerId = await switch.connect(remoteAddr) + stream = await switch.dial(remotePeerId, PingCodec) + pingDelay = await pingProtocol.ping(stream) + totalDelay = Moment.now() - dialingStart + await stream.close() + + echo Json.encode( + ResultJson( + handshakePlusOneRTTMillis: float(totalDelay.milliseconds), + pingRTTMilllis: float(pingDelay.milliseconds) + ) + ) + quit(0) + +discard waitFor(main().withTimeout(testTimeout)) +quit(1) diff --git a/tests/transport-interop/version.json b/tests/transport-interop/version.json new file mode 100644 index 000000000..d539e9584 --- /dev/null +++ b/tests/transport-interop/version.json @@ -0,0 +1,15 @@ +{ + "id": "nim-libp2p-head", + "containerImageID": "nim-libp2p-head", + "transports": [ + "tcp", + "ws" + ], + "secureChannels": [ + "noise" + ], + "muxers": [ + "mplex", + "yamux" + ] +}