mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
Add interoperability test for py-libp2p and js-libp2p with enhanced logging
This commit is contained in:
81
tests/interop/js_libp2p/README.md
Normal file
81
tests/interop/js_libp2p/README.md
Normal file
@ -0,0 +1,81 @@
|
||||
# py-libp2p and js-libp2p Interoperability Tests
|
||||
|
||||
This repository contains interoperability tests for py-libp2p and js-libp2p using the /ipfs/ping/1.0.0 protocol. The goal is to verify compatibility in stream multiplexing, protocol negotiation, ping handling, transport layer, and multiaddr parsing.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
- js_node/ping.js: JavaScript implementation of a ping server and client using libp2p.
|
||||
- py_node/ping.py: Python implementation of a ping server and client using py-libp2p.
|
||||
- scripts/run_test.sh: Shell script to automate running the server and client for testing.
|
||||
- README.md: This file.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.8+ with `py-libp2p` and dependencies (`pip install libp2p trio cryptography multiaddr`).
|
||||
- Node.js 16+ with `libp2p` dependencies (`npm install @libp2p/core @libp2p/tcp @chainsafe/libp2p-noise @chainsafe/libp2p-yamux @libp2p/ping @libp2p/identify @multiformats/multiaddr`).
|
||||
- Bash shell for running `run_test.sh`.
|
||||
|
||||
## Running Tests
|
||||
|
||||
1. Change directory:
|
||||
|
||||
```
|
||||
cd tests/interop/js_libp2p
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
|
||||
```
|
||||
For JavaScript: cd js_node && npm install && cd ...
|
||||
```
|
||||
|
||||
3. Run the automated test:
|
||||
|
||||
For Linux and Mac users:
|
||||
|
||||
```
|
||||
chmod +x scripts/run_test.sh
|
||||
./scripts/run_test.sh
|
||||
```
|
||||
|
||||
For Windows users:
|
||||
|
||||
```
|
||||
.\scripts\run_test.ps1
|
||||
```
|
||||
|
||||
This starts the Python server on port 8000 and runs the JavaScript client to send 5 pings.
|
||||
|
||||
## Debugging
|
||||
|
||||
- Logs are saved in py_node/py_server.log and js_node/js_client.log.
|
||||
- Check for:
|
||||
- Successful connection establishment.
|
||||
- Protocol negotiation (/ipfs/ping/1.0.0).
|
||||
- 32-byte payload echo in server logs.
|
||||
- RTT and payload hex in client logs.
|
||||
|
||||
## Test Plan
|
||||
|
||||
### The test verifies:
|
||||
|
||||
- Stream Multiplexer Compatibility: Yamux is used and negotiates correctly.
|
||||
- Multistream Protocol Negotiation: /ipfs/ping/1.0.0 is selected via multistream-select.
|
||||
- Ping Protocol Handler: Handles 32-byte payloads per the libp2p ping spec.
|
||||
- Transport Layer Support: TCP is used; WebSocket support is optional.
|
||||
- Multiaddr Parsing: Correctly resolves multiaddr strings.
|
||||
- Logging: Includes peer ID, RTT, and payload hex for debugging.
|
||||
|
||||
## Current Status
|
||||
|
||||
### Working:
|
||||
|
||||
- TCP transport and Noise encryption are functional.
|
||||
- Yamux multiplexing is implemented in both nodes.
|
||||
- Multiaddr parsing works correctly.
|
||||
- Logging provides detailed debug information.
|
||||
|
||||
## Not Working:
|
||||
|
||||
- Ping protocol handler fails to complete pings (JS client reports "operation aborted").
|
||||
- Potential issues with stream handling or protocol negotiation.
|
||||
4
tests/interop/js_libp2p/js_node/.gitIgnore
Normal file
4
tests/interop/js_libp2p/js_node/.gitIgnore
Normal file
@ -0,0 +1,4 @@
|
||||
/node_modules
|
||||
/package-lock.json
|
||||
/dist
|
||||
.log
|
||||
17
tests/interop/js_libp2p/js_node/.github/pull_request_template.md
vendored
Normal file
17
tests/interop/js_libp2p/js_node/.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# ⚠️ IMPORTANT ⚠️
|
||||
|
||||
# Please do not create a Pull Request for this repository
|
||||
|
||||
The contents of this repository are automatically synced from the parent [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples) so any changes made to the standalone repository will be lost after the next sync.
|
||||
|
||||
Please open a PR against [js-libp2p Examples](https://github.com/libp2p/js-libp2p-examples) instead.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||
|
||||
1. Fork the [js-libp2p Examples Project](https://github.com/libp2p/js-libp2p-examples)
|
||||
1. Create your Feature Branch (`git checkout -b feature/amazing-example`)
|
||||
1. Commit your Changes (`git commit -a -m 'feat: add some amazing example'`)
|
||||
1. Push to the Branch (`git push origin feature/amazing-example`)
|
||||
1. Open a Pull Request
|
||||
19
tests/interop/js_libp2p/js_node/.github/workflows/sync.yml
vendored
Normal file
19
tests/interop/js_libp2p/js_node/.github/workflows/sync.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: pull
|
||||
|
||||
on:
|
||||
workflow_dispatch
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Pull from another repository
|
||||
uses: ipfs-examples/actions-pull-directory-from-repo@main
|
||||
with:
|
||||
source-repo: libp2p/js-libp2p-examples
|
||||
source-folder-path: examples/${{ github.event.repository.name }}
|
||||
source-branch: main
|
||||
target-branch: main
|
||||
git-username: github-actions
|
||||
git-email: github-actions@github.com
|
||||
53
tests/interop/js_libp2p/js_node/README.md
Normal file
53
tests/interop/js_libp2p/js_node/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# @libp2p/example-chat <!-- omit in toc -->
|
||||
|
||||
[](http://libp2p.io/)
|
||||
[](https://discuss.libp2p.io)
|
||||
[](https://codecov.io/gh/libp2p/js-libp2p-examples)
|
||||
[](https://github.com/libp2p/js-libp2p-examples/actions/workflows/ci.yml?query=branch%3Amain)
|
||||
|
||||
> An example chat app using libp2p
|
||||
|
||||
## Table of contents <!-- omit in toc -->
|
||||
|
||||
- [Setup](#setup)
|
||||
- [Running](#running)
|
||||
- [Need help?](#need-help)
|
||||
- [License](#license)
|
||||
- [Contribution](#contribution)
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install example dependencies
|
||||
```console
|
||||
$ npm install
|
||||
```
|
||||
1. Open 2 terminal windows in the `./src` directory.
|
||||
|
||||
## Running
|
||||
|
||||
1. Run the listener in window 1, `node listener.js`
|
||||
1. Run the dialer in window 2, `node dialer.js`
|
||||
1. Wait until the two peers discover each other
|
||||
1. Type a message in either window and hit *enter*
|
||||
1. Tell yourself secrets to your hearts content!
|
||||
|
||||
## Need help?
|
||||
|
||||
- Read the [js-libp2p documentation](https://github.com/libp2p/js-libp2p/tree/main/doc)
|
||||
- Check out the [js-libp2p API docs](https://libp2p.github.io/js-libp2p/)
|
||||
- Check out the [general libp2p documentation](https://docs.libp2p.io) for tips, how-tos and more
|
||||
- Read the [libp2p specs](https://github.com/libp2p/specs)
|
||||
- Ask a question on the [js-libp2p discussion board](https://github.com/libp2p/js-libp2p/discussions)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>)
|
||||
- MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>)
|
||||
|
||||
## Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
39
tests/interop/js_libp2p/js_node/package.json
Normal file
39
tests/interop/js_libp2p/js_node/package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "@libp2p/example-chat",
|
||||
"version": "0.0.0",
|
||||
"description": "An example chat app using libp2p",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"homepage": "https://github.com/libp2p/js-libp2p-example-chat#readme",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/libp2p/js-libp2p-examples.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/libp2p/js-libp2p-examples/issues"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "test-node-example test/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@chainsafe/libp2p-noise": "^16.0.0",
|
||||
"@chainsafe/libp2p-yamux": "^7.0.0",
|
||||
"@libp2p/identify": "^3.0.33",
|
||||
"@libp2p/mdns": "^11.0.1",
|
||||
"@libp2p/ping": "^2.0.33",
|
||||
"@libp2p/tcp": "^10.0.0",
|
||||
"@libp2p/websockets": "^9.0.0",
|
||||
"@multiformats/multiaddr": "^12.3.1",
|
||||
"@nodeutils/defaults-deep": "^1.1.0",
|
||||
"it-length-prefixed": "^10.0.1",
|
||||
"it-map": "^3.0.3",
|
||||
"it-pipe": "^3.0.1",
|
||||
"libp2p": "^2.0.0",
|
||||
"p-defer": "^4.0.0",
|
||||
"uint8arrays": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"test-ipfs-example": "^1.1.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
204
tests/interop/js_libp2p/js_node/src/ping.js
Normal file
204
tests/interop/js_libp2p/js_node/src/ping.js
Normal file
@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createLibp2p } from 'libp2p'
|
||||
import { tcp } from '@libp2p/tcp'
|
||||
import { noise } from '@chainsafe/libp2p-noise'
|
||||
import { yamux } from '@chainsafe/libp2p-yamux'
|
||||
import { ping } from '@libp2p/ping'
|
||||
import { identify } from '@libp2p/identify'
|
||||
import { multiaddr } from '@multiformats/multiaddr'
|
||||
|
||||
async function createNode() {
|
||||
return await createLibp2p({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
transports: [
|
||||
tcp()
|
||||
],
|
||||
connectionEncrypters: [
|
||||
noise()
|
||||
],
|
||||
streamMuxers: [
|
||||
yamux()
|
||||
],
|
||||
services: {
|
||||
// Use ipfs prefix to match py-libp2p example
|
||||
ping: ping({
|
||||
protocolPrefix: 'ipfs',
|
||||
maxInboundStreams: 32,
|
||||
maxOutboundStreams: 64,
|
||||
timeout: 30000
|
||||
}),
|
||||
identify: identify()
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 0,
|
||||
maxConnections: 100,
|
||||
dialTimeout: 30000
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function runServer() {
|
||||
console.log('🚀 Starting js-libp2p ping server...')
|
||||
|
||||
const node = await createNode()
|
||||
await node.start()
|
||||
|
||||
console.log('✅ Server started!')
|
||||
console.log(`📋 Peer ID: ${node.peerId.toString()}`)
|
||||
console.log('📍 Listening addresses:')
|
||||
|
||||
node.getMultiaddrs().forEach(addr => {
|
||||
console.log(` ${addr.toString()}`)
|
||||
})
|
||||
|
||||
// Listen for connections
|
||||
node.addEventListener('peer:connect', (evt) => {
|
||||
console.log(`🔗 Peer connected: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
node.addEventListener('peer:disconnect', (evt) => {
|
||||
console.log(`❌ Peer disconnected: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
console.log('\n🎧 Server ready for ping requests...')
|
||||
console.log('Press Ctrl+C to exit')
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', async () => {
|
||||
console.log('\n🛑 Shutting down...')
|
||||
await node.stop()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
// Keep alive
|
||||
while (true) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
}
|
||||
|
||||
async function runClient(targetAddr, count = 5) {
|
||||
console.log('🚀 Starting js-libp2p ping client...')
|
||||
|
||||
const node = await createNode()
|
||||
await node.start()
|
||||
|
||||
console.log(`📋 Our Peer ID: ${node.peerId.toString()}`)
|
||||
console.log(`🎯 Target: ${targetAddr}`)
|
||||
|
||||
try {
|
||||
const ma = multiaddr(targetAddr)
|
||||
const targetPeerId = ma.getPeerId()
|
||||
|
||||
if (!targetPeerId) {
|
||||
throw new Error('Could not extract peer ID from multiaddr')
|
||||
}
|
||||
|
||||
console.log(`🎯 Target Peer ID: ${targetPeerId}`)
|
||||
console.log('🔗 Connecting to peer...')
|
||||
|
||||
const connection = await node.dial(ma)
|
||||
console.log('✅ Connection established!')
|
||||
console.log(`🔗 Connected to: ${connection.remotePeer.toString()}`)
|
||||
|
||||
// Add a small delay to let the connection fully establish
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
const rtts = []
|
||||
|
||||
for (let i = 1; i <= count; i++) {
|
||||
try {
|
||||
console.log(`\n🏓 Sending ping ${i}/${count}...`);
|
||||
console.log('[DEBUG] Attempting to open ping stream with protocol: /ipfs/ping/1.0.0');
|
||||
const start = Date.now()
|
||||
|
||||
const stream = await connection.newStream(['/ipfs/ping/1.0.0']).catch(err => {
|
||||
console.error(`[ERROR] Failed to open ping stream: ${err.message}`);
|
||||
throw err;
|
||||
});
|
||||
console.log('[DEBUG] Ping stream opened successfully');
|
||||
|
||||
const latency = await Promise.race([
|
||||
node.services.ping.ping(connection.remotePeer),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Ping timeout')), 30000) // Increased timeout
|
||||
)
|
||||
]).catch(err => {
|
||||
console.error(`[ERROR] Ping ${i} error: ${err.message}`);
|
||||
throw err;
|
||||
});
|
||||
|
||||
const rtt = Date.now() - start;
|
||||
|
||||
rtts.push(latency)
|
||||
console.log(`✅ Ping ${i} successful!`)
|
||||
console.log(` Reported latency: ${latency}ms`)
|
||||
console.log(` Measured RTT: ${rtt}ms`)
|
||||
|
||||
if (i < count) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Ping ${i} failed:`, error.message)
|
||||
// Try to continue with other pings
|
||||
}
|
||||
}
|
||||
|
||||
// Stats
|
||||
if (rtts.length > 0) {
|
||||
const avg = rtts.reduce((a, b) => a + b, 0) / rtts.length
|
||||
const min = Math.min(...rtts)
|
||||
const max = Math.max(...rtts)
|
||||
|
||||
console.log(`\n📊 Ping Statistics:`)
|
||||
console.log(` Packets: Sent=${count}, Received=${rtts.length}, Lost=${count - rtts.length}`)
|
||||
console.log(` Latency: min=${min}ms, avg=${avg.toFixed(2)}ms, max=${max}ms`)
|
||||
} else {
|
||||
console.log(`\n📊 All pings failed (${count} attempts)`)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Client error:', error.message)
|
||||
console.error('Stack:', error.stack)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
await node.stop()
|
||||
console.log('\n⏹️ Client stopped')
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log('Usage:')
|
||||
console.log(' node ping.js server # Start ping server')
|
||||
console.log(' node ping.js client <multiaddr> [count] # Ping a peer')
|
||||
console.log('')
|
||||
console.log('Examples:')
|
||||
console.log(' node ping.js server')
|
||||
console.log(' node ping.js client /ip4/127.0.0.1/tcp/12345/p2p/12D3Ko... 5')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const mode = args[0]
|
||||
|
||||
if (mode === 'server') {
|
||||
await runServer()
|
||||
} else if (mode === 'client') {
|
||||
if (args.length < 2) {
|
||||
console.error('❌ Client mode requires target multiaddr')
|
||||
process.exit(1)
|
||||
}
|
||||
const targetAddr = args[1]
|
||||
const count = parseInt(args[2]) || 5
|
||||
await runClient(targetAddr, count)
|
||||
} else {
|
||||
console.error('❌ Invalid mode. Use "server" or "client"')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
241
tests/interop/js_libp2p/js_node/src/ping_client.js
Normal file
241
tests/interop/js_libp2p/js_node/src/ping_client.js
Normal file
@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createLibp2p } from 'libp2p'
|
||||
import { tcp } from '@libp2p/tcp'
|
||||
import { noise } from '@chainsafe/libp2p-noise'
|
||||
import { yamux } from '@chainsafe/libp2p-yamux'
|
||||
import { ping } from '@libp2p/ping'
|
||||
import { identify } from '@libp2p/identify'
|
||||
import { multiaddr } from '@multiformats/multiaddr'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
const logsDir = path.join(process.cwd(), '../logs')
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true })
|
||||
}
|
||||
|
||||
// Setup logging
|
||||
const logFile = path.join(logsDir, 'js_ping_client.log')
|
||||
const logStream = fs.createWriteStream(logFile, { flags: 'w' })
|
||||
|
||||
function log(message) {
|
||||
const timestamp = new Date().toISOString()
|
||||
const logLine = `${timestamp} - ${message}\n`
|
||||
logStream.write(logLine)
|
||||
console.log(message)
|
||||
}
|
||||
|
||||
async function createNode() {
|
||||
log('🔧 Creating libp2p node...')
|
||||
|
||||
const node = await createLibp2p({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0'] // Random port
|
||||
},
|
||||
transports: [
|
||||
tcp()
|
||||
],
|
||||
connectionEncrypters: [
|
||||
noise()
|
||||
],
|
||||
streamMuxers: [
|
||||
yamux()
|
||||
],
|
||||
services: {
|
||||
ping: ping({
|
||||
protocolPrefix: 'ipfs', // Use ipfs prefix to match py-libp2p
|
||||
maxInboundStreams: 32,
|
||||
maxOutboundStreams: 64,
|
||||
timeout: 30000,
|
||||
runOnTransientConnection: true
|
||||
}),
|
||||
identify: identify()
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 0,
|
||||
maxConnections: 100,
|
||||
dialTimeout: 30000,
|
||||
maxParallelDials: 10
|
||||
}
|
||||
})
|
||||
|
||||
log('✅ Node created successfully')
|
||||
return node
|
||||
}
|
||||
|
||||
async function runClient(targetAddr, count = 5) {
|
||||
log('🚀 Starting js-libp2p ping client...')
|
||||
|
||||
const node = await createNode()
|
||||
|
||||
// Add connection event listeners
|
||||
node.addEventListener('peer:connect', (evt) => {
|
||||
log(`🔗 Connected to peer: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
node.addEventListener('peer:disconnect', (evt) => {
|
||||
log(`❌ Disconnected from peer: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
await node.start()
|
||||
log('✅ Node started')
|
||||
|
||||
log(`📋 Our Peer ID: ${node.peerId.toString()}`)
|
||||
log(`🎯 Target: ${targetAddr}`)
|
||||
|
||||
try {
|
||||
const ma = multiaddr(targetAddr)
|
||||
const targetPeerId = ma.getPeerId()
|
||||
|
||||
if (!targetPeerId) {
|
||||
throw new Error('Could not extract peer ID from multiaddr')
|
||||
}
|
||||
|
||||
log(`🎯 Target Peer ID: ${targetPeerId}`)
|
||||
|
||||
// Parse multiaddr components for debugging
|
||||
const components = ma.toString().split('/')
|
||||
log(`📍 Target components: ${components.join(' → ')}`)
|
||||
|
||||
log('🔗 Attempting to dial peer...')
|
||||
const connection = await node.dial(ma)
|
||||
log('✅ Connection established!')
|
||||
log(`🔗 Connected to: ${connection.remotePeer.toString()}`)
|
||||
log(`🔗 Connection status: ${connection.status}`)
|
||||
log(`🔗 Connection direction: ${connection.direction}`)
|
||||
|
||||
// List available protocols
|
||||
if (connection.remoteAddr) {
|
||||
log(`🌐 Remote address: ${connection.remoteAddr.toString()}`)
|
||||
}
|
||||
|
||||
// Wait for connection to stabilize
|
||||
log('⏳ Waiting for connection to stabilize...')
|
||||
await new Promise(resolve => setTimeout(resolve, 2000))
|
||||
|
||||
// Attempt ping sequence
|
||||
log(`\n🏓 Starting ping sequence (${count} pings)...`)
|
||||
const rtts = []
|
||||
|
||||
for (let i = 1; i <= count; i++) {
|
||||
try {
|
||||
log(`\n🏓 Sending ping ${i}/${count}...`)
|
||||
const start = Date.now()
|
||||
|
||||
// Create a more robust ping with better error handling
|
||||
const pingPromise = node.services.ping.ping(connection.remotePeer)
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Ping timeout (15s)')), 15000)
|
||||
)
|
||||
|
||||
const latency = await Promise.race([pingPromise, timeoutPromise])
|
||||
const totalRtt = Date.now() - start
|
||||
|
||||
rtts.push(latency)
|
||||
log(`✅ Ping ${i} successful!`)
|
||||
log(` Reported latency: ${latency}ms`)
|
||||
log(` Total RTT: ${totalRtt}ms`)
|
||||
|
||||
// Wait between pings
|
||||
if (i < count) {
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
} catch (error) {
|
||||
log(`❌ Ping ${i} failed: ${error.message}`)
|
||||
log(` Error type: ${error.constructor.name}`)
|
||||
if (error.code) {
|
||||
log(` Error code: ${error.code}`)
|
||||
}
|
||||
|
||||
// Check if connection is still alive
|
||||
if (connection.status !== 'open') {
|
||||
log(`⚠️ Connection status changed to: ${connection.status}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print statistics
|
||||
if (rtts.length > 0) {
|
||||
const avg = rtts.reduce((a, b) => a + b, 0) / rtts.length
|
||||
const min = Math.min(...rtts)
|
||||
const max = Math.max(...rtts)
|
||||
const lossRate = ((count - rtts.length) / count * 100).toFixed(1)
|
||||
|
||||
log(`\n📊 Ping Statistics:`)
|
||||
log(` Packets: Sent=${count}, Received=${rtts.length}, Lost=${count - rtts.length}`)
|
||||
log(` Loss rate: ${lossRate}%`)
|
||||
log(` Latency: min=${min}ms, avg=${avg.toFixed(2)}ms, max=${max}ms`)
|
||||
} else {
|
||||
log(`\n📊 All pings failed (${count} attempts)`)
|
||||
}
|
||||
|
||||
// Close connection gracefully
|
||||
log('\n🔒 Closing connection...')
|
||||
await connection.close()
|
||||
|
||||
} catch (error) {
|
||||
log(`❌ Client error: ${error.message}`)
|
||||
log(` Error type: ${error.constructor.name}`)
|
||||
if (error.stack) {
|
||||
log(` Stack trace: ${error.stack}`)
|
||||
}
|
||||
process.exit(1)
|
||||
} finally {
|
||||
log('🛑 Stopping node...')
|
||||
await node.stop()
|
||||
log('⏹️ Client stopped')
|
||||
logStream.end()
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2)
|
||||
|
||||
if (args.length === 0) {
|
||||
console.log('Usage:')
|
||||
console.log(' node ping-client.js <target-multiaddr> [count]')
|
||||
console.log('')
|
||||
console.log('Examples:')
|
||||
console.log(' node ping-client.js /ip4/127.0.0.1/tcp/8000/p2p/QmExample... 5')
|
||||
console.log(' node ping-client.js /ip4/127.0.0.1/tcp/8000/p2p/QmExample... 10')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const targetAddr = args[0]
|
||||
const count = parseInt(args[1]) || 5
|
||||
|
||||
if (count <= 0 || count > 100) {
|
||||
console.error('❌ Count must be between 1 and 100')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
await runClient(targetAddr, count)
|
||||
}
|
||||
|
||||
// Handle graceful shutdown
|
||||
process.on('SIGINT', () => {
|
||||
log('\n👋 Shutting down...')
|
||||
logStream.end()
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
log(`💥 Uncaught exception: ${error.message}`)
|
||||
if (error.stack) {
|
||||
log(`Stack: ${error.stack}`)
|
||||
}
|
||||
logStream.end()
|
||||
process.exit(1)
|
||||
})
|
||||
|
||||
main().catch((error) => {
|
||||
log(`💥 Fatal error: ${error.message}`)
|
||||
if (error.stack) {
|
||||
log(`Stack: ${error.stack}`)
|
||||
}
|
||||
logStream.end()
|
||||
process.exit(1)
|
||||
})
|
||||
167
tests/interop/js_libp2p/js_node/src/ping_server.js
Normal file
167
tests/interop/js_libp2p/js_node/src/ping_server.js
Normal file
@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { createLibp2p } from 'libp2p'
|
||||
import { tcp } from '@libp2p/tcp'
|
||||
import { noise } from '@chainsafe/libp2p-noise'
|
||||
import { yamux } from '@chainsafe/libp2p-yamux'
|
||||
import { ping } from '@libp2p/ping'
|
||||
import { identify } from '@libp2p/identify'
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
// Create logs directory if it doesn't exist
|
||||
const logsDir = path.join(process.cwd(), '../logs')
|
||||
if (!fs.existsSync(logsDir)) {
|
||||
fs.mkdirSync(logsDir, { recursive: true })
|
||||
}
|
||||
|
||||
// Setup logging
|
||||
const logFile = path.join(logsDir, 'js_ping_server.log')
|
||||
const logStream = fs.createWriteStream(logFile, { flags: 'w' })
|
||||
|
||||
function log(message) {
|
||||
const timestamp = new Date().toISOString()
|
||||
const logLine = `${timestamp} - ${message}\n`
|
||||
logStream.write(logLine)
|
||||
console.log(message)
|
||||
}
|
||||
|
||||
async function createNode(port) {
|
||||
log('🔧 Creating libp2p node...')
|
||||
|
||||
const node = await createLibp2p({
|
||||
addresses: {
|
||||
listen: [`/ip4/0.0.0.0/tcp/${port}`]
|
||||
},
|
||||
transports: [
|
||||
tcp()
|
||||
],
|
||||
connectionEncrypters: [
|
||||
noise()
|
||||
],
|
||||
streamMuxers: [
|
||||
yamux()
|
||||
],
|
||||
services: {
|
||||
ping: ping({
|
||||
protocolPrefix: 'ipfs', // Use ipfs prefix to match py-libp2p
|
||||
maxInboundStreams: 32,
|
||||
maxOutboundStreams: 64,
|
||||
timeout: 30000,
|
||||
runOnTransientConnection: true
|
||||
}),
|
||||
identify: identify()
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 0,
|
||||
maxConnections: 100,
|
||||
dialTimeout: 30000,
|
||||
maxParallelDials: 10
|
||||
}
|
||||
})
|
||||
|
||||
log('✅ Node created successfully')
|
||||
return node
|
||||
}
|
||||
|
||||
async function runServer(port) {
|
||||
log('🚀 Starting js-libp2p ping server...')
|
||||
|
||||
const node = await createNode(port)
|
||||
|
||||
// Add connection event listeners
|
||||
node.addEventListener('peer:connect', (evt) => {
|
||||
log(`🔗 New peer connected: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
node.addEventListener('peer:disconnect', (evt) => {
|
||||
log(`❌ Peer disconnected: ${evt.detail.toString()}`)
|
||||
})
|
||||
|
||||
// Add protocol handler for incoming streams
|
||||
node.addEventListener('peer:identify', (evt) => {
|
||||
log(`🔍 Peer identified: ${evt.detail.peerId.toString()}`)
|
||||
log(` Protocols: ${evt.detail.protocols.join(', ')}`)
|
||||
log(` Listen addresses: ${evt.detail.listenAddrs.map(addr => addr.toString()).join(', ')}`)
|
||||
})
|
||||
|
||||
await node.start()
|
||||
log('✅ Node started')
|
||||
|
||||
const peerId = node.peerId.toString()
|
||||
const listenAddrs = node.getMultiaddrs()
|
||||
|
||||
log(`📋 Peer ID: ${peerId}`)
|
||||
log(`🌐 Listen addresses:`)
|
||||
listenAddrs.forEach(addr => {
|
||||
log(` ${addr.toString()}`)
|
||||
})
|
||||
|
||||
// Find the main TCP address for easy copy-paste
|
||||
const tcpAddr = listenAddrs.find(addr =>
|
||||
addr.toString().includes('/tcp/') &&
|
||||
!addr.toString().includes('/ws')
|
||||
)
|
||||
|
||||
if (tcpAddr) {
|
||||
log(`\n🧪 Test with py-libp2p:`)
|
||||
log(` python ping_client.py ${tcpAddr.toString()}`)
|
||||
log(`\n🧪 Test with js-libp2p:`)
|
||||
log(` node ping-client.js ${tcpAddr.toString()}`)
|
||||
}
|
||||
|
||||
log(`\n🏓 Ping service is running with protocol: /ipfs/ping/1.0.0`)
|
||||
log(`🔐 Security: Noise encryption`)
|
||||
log(`🚇 Muxer: Yamux stream multiplexing`)
|
||||
log(`\n⏳ Waiting for connections...`)
|
||||
log('Press Ctrl+C to exit')
|
||||
|
||||
// Keep the server running
|
||||
return new Promise((resolve, reject) => {
|
||||
process.on('SIGINT', () => {
|
||||
log('\n🛑 Shutting down server...')
|
||||
node.stop().then(() => {
|
||||
log('⏹️ Server stopped')
|
||||
logStream.end()
|
||||
resolve()
|
||||
}).catch(reject)
|
||||
})
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
log(`💥 Uncaught exception: ${error.message}`)
|
||||
if (error.stack) {
|
||||
log(`Stack: ${error.stack}`)
|
||||
}
|
||||
logStream.end()
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2)
|
||||
const port = parseInt(args[0]) || 9000
|
||||
|
||||
if (port <= 0 || port > 65535) {
|
||||
console.error('❌ Port must be between 1 and 65535')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
try {
|
||||
await runServer(port)
|
||||
} catch (error) {
|
||||
console.error(`💥 Fatal error: ${error.message}`)
|
||||
if (error.stack) {
|
||||
console.error(`Stack: ${error.stack}`)
|
||||
}
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(`💥 Fatal error: ${error.message}`)
|
||||
if (error.stack) {
|
||||
console.error(`Stack: ${error.stack}`)
|
||||
}
|
||||
process.exit(1)
|
||||
})
|
||||
398
tests/interop/js_libp2p/py_node/ping.py
Normal file
398
tests/interop/js_libp2p/py_node/ping.py
Normal file
@ -0,0 +1,398 @@
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
from cryptography.hazmat.primitives.asymmetric import (
|
||||
x25519,
|
||||
)
|
||||
import multiaddr
|
||||
import trio
|
||||
|
||||
from libp2p import (
|
||||
generate_new_rsa_identity,
|
||||
new_host,
|
||||
)
|
||||
from libp2p.custom_types import (
|
||||
TProtocol,
|
||||
)
|
||||
from libp2p.network.stream.net_stream import (
|
||||
INetStream,
|
||||
)
|
||||
from libp2p.peer.peerinfo import (
|
||||
info_from_p2p_addr,
|
||||
)
|
||||
from libp2p.security.noise.transport import Transport as NoiseTransport
|
||||
from libp2p.stream_muxer.yamux.yamux import (
|
||||
Yamux,
|
||||
)
|
||||
from libp2p.stream_muxer.yamux.yamux import PROTOCOL_ID as YAMUX_PROTOCOL_ID
|
||||
|
||||
# Configure detailed logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.StreamHandler(),
|
||||
logging.FileHandler("ping_debug.log", mode="w", encoding="utf-8"),
|
||||
],
|
||||
)
|
||||
|
||||
PING_PROTOCOL_ID = TProtocol("/ipfs/ping/1.0.0")
|
||||
PING_LENGTH = 32
|
||||
RESP_TIMEOUT = 60
|
||||
|
||||
|
||||
async def handle_ping(stream: INetStream) -> None:
|
||||
"""Handle incoming ping requests from js-libp2p clients"""
|
||||
peer_id = stream.muxed_conn.peer_id
|
||||
print(f"[INFO] New ping stream opened by {peer_id}")
|
||||
logging.info(f"Ping handler called for peer {peer_id}")
|
||||
|
||||
ping_count = 0
|
||||
|
||||
try:
|
||||
while True:
|
||||
try:
|
||||
print(f"[INFO] Waiting for ping data from {peer_id}...")
|
||||
logging.debug(f"Stream state: {stream}")
|
||||
data = await stream.read(PING_LENGTH)
|
||||
|
||||
if not data:
|
||||
print(
|
||||
f"[INFO] No data received,"
|
||||
f"connection likely closed by {peer_id}"
|
||||
)
|
||||
logging.debug("No data received, stream closed")
|
||||
break
|
||||
|
||||
if len(data) == 0:
|
||||
print(f"[INFO] Empty data received, connection closed by {peer_id}")
|
||||
logging.debug("Empty data received")
|
||||
break
|
||||
|
||||
ping_count += 1
|
||||
print(
|
||||
f"[PING {ping_count}] Received ping from {peer_id}:"
|
||||
f"{len(data)} bytes"
|
||||
)
|
||||
logging.debug(f"Ping data: {data.hex()}")
|
||||
|
||||
await stream.write(data)
|
||||
print(f"[PING {ping_count}] Echoed ping back to {peer_id}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Error in ping loop with {peer_id}: {e}")
|
||||
logging.exception("Ping loop error")
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Error handling ping from {peer_id}: {e}")
|
||||
logging.exception("Ping handler error")
|
||||
finally:
|
||||
try:
|
||||
print(f"[INFO] Closing ping stream with {peer_id}")
|
||||
await stream.close()
|
||||
except Exception as e:
|
||||
logging.debug(f"Error closing stream: {e}")
|
||||
|
||||
print(f"[INFO] Ping session completed with {peer_id} ({ping_count} pings)")
|
||||
|
||||
|
||||
async def send_ping_sequence(stream: INetStream, count: int = 5) -> None:
|
||||
"""Send a sequence of pings compatible with js-libp2p."""
|
||||
peer_id = stream.muxed_conn.peer_id
|
||||
print(f"[INFO] Starting ping sequence to {peer_id} ({count} pings)")
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
rtts = []
|
||||
|
||||
for i in range(1, count + 1):
|
||||
try:
|
||||
payload = os.urandom(PING_LENGTH)
|
||||
print(f"[PING {i}/{count}] Sending ping to {peer_id}")
|
||||
logging.debug(f"Sending payload: {payload.hex()}")
|
||||
start_time = time.time()
|
||||
|
||||
await stream.write(payload)
|
||||
|
||||
with trio.fail_after(RESP_TIMEOUT):
|
||||
response = await stream.read(PING_LENGTH)
|
||||
|
||||
end_time = time.time()
|
||||
rtt = (end_time - start_time) * 1000
|
||||
|
||||
if (
|
||||
response
|
||||
and len(response) >= PING_LENGTH
|
||||
and response[:PING_LENGTH] == payload
|
||||
):
|
||||
rtts.append(rtt)
|
||||
print(f"[PING {i}] Successful! RTT: {rtt:.2f}ms")
|
||||
else:
|
||||
print(f"[ERROR] Ping {i} failed: response mismatch or incomplete")
|
||||
if response:
|
||||
logging.debug(f"Expected: {payload.hex()}")
|
||||
logging.debug(f"Received: {response.hex()}")
|
||||
|
||||
if i < count:
|
||||
await trio.sleep(1)
|
||||
|
||||
except trio.TooSlowError:
|
||||
print(f"[ERROR] Ping {i} timed out after {RESP_TIMEOUT}s")
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Ping {i} failed: {e}")
|
||||
logging.exception(f"Ping {i} error")
|
||||
|
||||
if rtts:
|
||||
avg_rtt = sum(rtts) / len(rtts)
|
||||
min_rtt = min(rtts)
|
||||
max_rtts = max(rtts)
|
||||
success_count = len(rtts)
|
||||
loss_rate = ((count - success_count) / count) * 100
|
||||
|
||||
print(
|
||||
f" Packets: Sent={count}, Received={success_count},"
|
||||
f" Lost={count - success_count}"
|
||||
)
|
||||
print(f" Loss rate: {loss_rate:.1f}%")
|
||||
print(
|
||||
f" RTT: min={min_rtt:.2f}ms, avg={avg_rtt:.2f}ms," f"max={max_rtts:.2f}ms"
|
||||
)
|
||||
else:
|
||||
print(f"\n[STATS] All pings failed ({count} attempts)")
|
||||
|
||||
|
||||
def create_noise_keypair():
|
||||
try:
|
||||
x25519_private_key = x25519.X25519PrivateKey.generate()
|
||||
|
||||
class NoisePrivateKey:
|
||||
def __init__(self, key):
|
||||
self._key = key
|
||||
|
||||
def to_bytes(self):
|
||||
return self._key.private_bytes_raw()
|
||||
|
||||
def public_key(self):
|
||||
return NoisePublicKey(self._key.public_key())
|
||||
|
||||
def get_public_key(self):
|
||||
return NoisePublicKey(self._key.public_key())
|
||||
|
||||
class NoisePublicKey:
|
||||
def __init__(self, key):
|
||||
self._key = key
|
||||
|
||||
def to_bytes(self):
|
||||
return self._key.public_bytes_raw()
|
||||
|
||||
return NoisePrivateKey(x25519_private_key)
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to create Noise keypair: {e}")
|
||||
return None
|
||||
|
||||
|
||||
async def run_server(port: int) -> None:
|
||||
"""Run ping server that accepts connections from js-libp2p clients."""
|
||||
listen_addr = multiaddr.Multiaddr(f"/ip4/0.0.0.0/tcp/{port}")
|
||||
|
||||
key_pair = generate_new_rsa_identity()
|
||||
logging.debug("Generated RSA keypair")
|
||||
|
||||
noise_privkey = create_noise_keypair()
|
||||
logging.debug("Generated Noise keypair")
|
||||
|
||||
noise_transport = NoiseTransport(key_pair, noise_privkey=noise_privkey)
|
||||
logging.debug(f"Noise transport initialized: {noise_transport}")
|
||||
sec_opt = {TProtocol("/noise"): noise_transport}
|
||||
muxer_opt = {TProtocol(YAMUX_PROTOCOL_ID): Yamux}
|
||||
|
||||
logging.info(f"Using muxer: {muxer_opt}")
|
||||
|
||||
host = new_host(key_pair=key_pair, sec_opt=sec_opt, muxer_opt=muxer_opt)
|
||||
|
||||
print("[INFO] Starting py-libp2p ping server...")
|
||||
|
||||
async with host.run(listen_addrs=[listen_addr]):
|
||||
print(f"[INFO] Registering ping handler for protocol: {PING_PROTOCOL_ID}")
|
||||
host.set_stream_handler(PING_PROTOCOL_ID, handle_ping)
|
||||
|
||||
alt_protocols = [
|
||||
TProtocol("/ping/1.0.0"),
|
||||
TProtocol("/libp2p/ping/1.0.0"),
|
||||
]
|
||||
|
||||
for alt_proto in alt_protocols:
|
||||
print(f"[INFO] Also registering handler for: {alt_proto}")
|
||||
host.set_stream_handler(alt_proto, handle_ping)
|
||||
|
||||
print("[INFO] Server started!")
|
||||
print(f"[INFO] Peer ID: {host.get_id()}")
|
||||
print(f"[INFO] Listening: /ip4/0.0.0.0/tcp/{port}")
|
||||
print(f"[INFO] Primary Protocol: {PING_PROTOCOL_ID}")
|
||||
# print(f"[INFO] Security: Noise encryption")
|
||||
# print(f"[INFO] Muxer: Yamux stream multiplexing")
|
||||
|
||||
print("\n[INFO] Registered protocols:")
|
||||
print(f" - {PING_PROTOCOL_ID}")
|
||||
for proto in alt_protocols:
|
||||
print(f" - {proto}")
|
||||
|
||||
peer_id = host.get_id()
|
||||
print("\n[TEST] Test with js-libp2p:")
|
||||
print(f" node ping.js client /ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}")
|
||||
|
||||
print("\n[TEST] Test with py-libp2p:")
|
||||
print(f" python ping.py client /ip4/127.0.0.1/tcp/{port}/p2p/{peer_id}")
|
||||
|
||||
print("\n[INFO] Waiting for connections...")
|
||||
print("Press Ctrl+C to exit")
|
||||
|
||||
await trio.sleep_forever()
|
||||
|
||||
|
||||
async def run_client(destination: str, count: int = 5) -> None:
|
||||
"""Run ping client to test connectivity with another peer."""
|
||||
listen_addr = multiaddr.Multiaddr("/ip4/0.0.0.0/tcp/0")
|
||||
|
||||
key_pair = generate_new_rsa_identity()
|
||||
logging.debug("Generated RSA keypair")
|
||||
|
||||
noise_privkey = create_noise_keypair()
|
||||
logging.debug("Generated Noise keypair")
|
||||
|
||||
noise_transport = NoiseTransport(key_pair, noise_privkey=noise_privkey)
|
||||
logging.debug(f"Noise transport initialized: {noise_transport}")
|
||||
sec_opt = {TProtocol("/noise"): noise_transport}
|
||||
muxer_opt = {TProtocol(YAMUX_PROTOCOL_ID): Yamux}
|
||||
|
||||
logging.info(f"Using muxer: {muxer_opt}")
|
||||
|
||||
host = new_host(key_pair=key_pair, sec_opt=sec_opt, muxer_opt=muxer_opt)
|
||||
|
||||
print("[INFO] Starting py-libp2p ping client...")
|
||||
|
||||
async with host.run(listen_addrs=[listen_addr]):
|
||||
print(f"[INFO] Our Peer ID: {host.get_id()}")
|
||||
print(f"[INFO] Target: {destination}")
|
||||
print("[INFO] Security: Noise encryption")
|
||||
print("[INFO] Muxer: Yamux stream multiplexing")
|
||||
|
||||
try:
|
||||
maddr = multiaddr.Multiaddr(destination)
|
||||
info = info_from_p2p_addr(maddr)
|
||||
target_peer_id = info.peer_id
|
||||
|
||||
print(f"[INFO] Target Peer ID: {target_peer_id}")
|
||||
print("[INFO] Connecting to peer...")
|
||||
|
||||
await host.connect(info)
|
||||
print("[INFO] Connection established!")
|
||||
|
||||
protocols_to_try = [
|
||||
PING_PROTOCOL_ID,
|
||||
TProtocol("/ping/1.0.0"),
|
||||
TProtocol("/libp2p/ping/1.0.0"),
|
||||
]
|
||||
|
||||
stream = None
|
||||
|
||||
for proto in protocols_to_try:
|
||||
try:
|
||||
print(f"[INFO] Trying to open stream with protocol: {proto}")
|
||||
stream = await host.new_stream(target_peer_id, [proto])
|
||||
print(f"[INFO] Stream opened with protocol: {proto}")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Failed to open stream with {proto}: {e}")
|
||||
continue
|
||||
|
||||
if not stream:
|
||||
print("[ERROR] Failed to open stream with any ping protocol")
|
||||
return 1
|
||||
|
||||
await send_ping_sequence(stream, count)
|
||||
|
||||
await stream.close()
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Client error: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
print("\n[INFO] Client stopped")
|
||||
return 0
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Main function with argument parsing."""
|
||||
description = """
|
||||
py-libp2p ping tool for interoperability testing with js-libp2p.
|
||||
Uses Noise encryption and Yamux multiplexing for compatibility.
|
||||
|
||||
Server mode: Listens for ping requests from js-libp2p or py-libp2p clients.
|
||||
Client mode: Sends ping requests to js-libp2p or py-libp2p servers.
|
||||
"""
|
||||
|
||||
example_maddr = (
|
||||
"/ip4/127.0.0.1/tcp/8000/p2p/QmQn4SwGkDZKkUEpBRBvTmheQycxAHJUNmVEnjA2v1qe8Q"
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=description,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=f"""
|
||||
Examples:
|
||||
python ping.py server # Start server on port 8000
|
||||
python ping.py server --port 9000 # Start server on port 9000
|
||||
python ping.py client {example_maddr}
|
||||
python ping.py client {example_maddr} --count 10
|
||||
""",
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers(dest="mode", help="Operation mode")
|
||||
|
||||
server_parser = subparsers.add_parser("server", help="Run as ping server")
|
||||
server_parser.add_argument(
|
||||
"--port", "-p", type=int, default=8000, help="Port to listen on (default: 8000)"
|
||||
)
|
||||
|
||||
client_parser = subparsers.add_parser("client", help="Run as ping client")
|
||||
client_parser.add_argument("destination", help="Target peer multiaddr")
|
||||
client_parser.add_argument(
|
||||
"--count",
|
||||
"-c",
|
||||
type=int,
|
||||
default=5,
|
||||
help="Number of pings to send (default: 5)",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.mode:
|
||||
parser.print_help()
|
||||
return 1
|
||||
|
||||
try:
|
||||
if args.mode == "server":
|
||||
trio.run(run_server, args.port)
|
||||
elif args.mode == "client":
|
||||
return trio.run(run_client, args.destination, args.count)
|
||||
except KeyboardInterrupt:
|
||||
print("\n[INFO] Goodbye!")
|
||||
return 0
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Fatal error: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
194
tests/interop/js_libp2p/scripts/run_test.ps1
Normal file
194
tests/interop/js_libp2p/scripts/run_test.ps1
Normal file
@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
# run_test.ps1 - libp2p Interoperability Test Runner (PowerShell)
|
||||
# Tests py-libp2p <-> js-libp2p ping communication
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# Colors for output
|
||||
$Red = "`e[31m"
|
||||
$Green = "`e[32m"
|
||||
$Yellow = "`e[33m"
|
||||
$Blue = "`e[34m"
|
||||
$Cyan = "`e[36m"
|
||||
$Reset = "`e[0m"
|
||||
|
||||
function Write-ColorOutput {
|
||||
param([string]$Message, [string]$Color = $Reset)
|
||||
Write-Host "${Color}${Message}${Reset}"
|
||||
}
|
||||
|
||||
Write-ColorOutput "[CHECK] Checking prerequisites..." $Cyan
|
||||
if (-not (Get-Command python -ErrorAction SilentlyContinue)) {
|
||||
Write-ColorOutput "[ERROR] Python not found. Install Python 3.7+" $Red
|
||||
exit 1
|
||||
}
|
||||
if (-not (Get-Command node -ErrorAction SilentlyContinue)) {
|
||||
Write-ColorOutput "[ERROR] Node.js not found. Install Node.js 16+" $Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-ColorOutput "[CHECK] Checking port 8000..." $Blue
|
||||
$portCheck = netstat -a -n -o | findstr :8000
|
||||
if ($portCheck) {
|
||||
Write-ColorOutput "[ERROR] Port 8000 in use. Free the port." $Red
|
||||
Write-ColorOutput $portCheck $Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-ColorOutput "[DEBUG] Cleaning up Python processes..." $Blue
|
||||
Get-Process -Name "python" -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -like "*ping.py*" } | Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
|
||||
Write-ColorOutput "[PYTHON] Starting server on port 8000..." $Yellow
|
||||
Set-Location -Path "py_node"
|
||||
$pyLogFile = "py_server_8000.log"
|
||||
$pyErrLogFile = "py_server_8000.log.err"
|
||||
$pyDebugLogFile = "ping_debug.log"
|
||||
|
||||
if (Test-Path $pyLogFile) { Remove-Item $pyLogFile -Force -ErrorAction SilentlyContinue }
|
||||
if (Test-Path $pyErrLogFile) { Remove-Item $pyErrLogFile -Force -ErrorAction SilentlyContinue }
|
||||
if (Test-Path $pyDebugLogFile) { Remove-Item $pyDebugLogFile -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
$pyProcess = Start-Process -FilePath "python" -ArgumentList "-u", "ping.py", "server", "--port", "8000" -NoNewWindow -PassThru -RedirectStandardOutput $pyLogFile -RedirectStandardError $pyErrLogFile
|
||||
Write-ColorOutput "[DEBUG] Python server PID: $($pyProcess.Id)" $Blue
|
||||
Write-ColorOutput "[DEBUG] Python logs: $((Get-Location).Path)\$pyLogFile, $((Get-Location).Path)\$pyErrLogFile, $((Get-Location).Path)\$pyDebugLogFile" $Blue
|
||||
|
||||
$timeoutSeconds = 20
|
||||
$startTime = Get-Date
|
||||
$serverStarted = $false
|
||||
|
||||
while (((Get-Date) - $startTime).TotalSeconds -lt $timeoutSeconds -and -not $serverStarted) {
|
||||
if (Test-Path $pyLogFile) {
|
||||
$content = Get-Content $pyLogFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($content -match "Server started|Listening") {
|
||||
$serverStarted = $true
|
||||
Write-ColorOutput "[OK] Python server started" $Green
|
||||
}
|
||||
}
|
||||
if (Test-Path $pyErrLogFile) {
|
||||
$errContent = Get-Content $pyErrLogFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($errContent) {
|
||||
Write-ColorOutput "[DEBUG] Error log: $errContent" $Yellow
|
||||
}
|
||||
}
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
|
||||
if (-not $serverStarted) {
|
||||
Write-ColorOutput "[ERROR] Python server failed to start" $Red
|
||||
Write-ColorOutput "[DEBUG] Logs:" $Yellow
|
||||
if (Test-Path $pyLogFile) { Get-Content $pyLogFile | Write-ColorOutput -Color $Yellow }
|
||||
if (Test-Path $pyErrLogFile) { Get-Content $pyErrLogFile | Write-ColorOutput -Color $Yellow }
|
||||
if (Test-Path $pyDebugLogFile) { Get-Content $pyDebugLogFile | Write-ColorOutput -Color $Yellow }
|
||||
Write-ColorOutput "[DEBUG] Trying foreground run..." $Yellow
|
||||
python -u ping.py server --port 8000
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Extract Peer ID
|
||||
$peerInfo = $null
|
||||
if (Test-Path $pyLogFile) {
|
||||
$content = Get-Content $pyLogFile -Raw
|
||||
$peerIdPattern = "Peer ID:\s*([A-Za-z0-9]+)"
|
||||
$peerIdMatch = [regex]::Match($content, $peerIdPattern)
|
||||
if ($peerIdMatch.Success) {
|
||||
$peerId = $peerIdMatch.Groups[1].Value
|
||||
$peerInfo = @{
|
||||
PeerId = $peerId
|
||||
MultiAddr = "/ip4/127.0.0.1/tcp/8000/p2p/$peerId"
|
||||
}
|
||||
Write-ColorOutput "[OK] Peer ID: $peerId" $Cyan
|
||||
Write-ColorOutput "[OK] MultiAddr: $($peerInfo.MultiAddr)" $Cyan
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $peerInfo) {
|
||||
Write-ColorOutput "[ERROR] Could not extract Peer ID" $Red
|
||||
if (Test-Path $pyLogFile) { Get-Content $pyLogFile | Write-ColorOutput -Color $Yellow }
|
||||
if (Test-Path $pyErrLogFile) { Get-Content $pyErrLogFile | Write-ColorOutput -Color $Yellow }
|
||||
if (Test-Path $pyDebugLogFile) { Get-Content $pyDebugLogFile | Write-ColorOutput -Color $Yellow }
|
||||
Stop-Process -Id $pyProcess.Id -Force -ErrorAction SilentlyContinue
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Start JavaScript client
|
||||
Write-ColorOutput "[JAVASCRIPT] Starting client..." $Yellow
|
||||
Set-Location -Path "../js_node"
|
||||
$jsLogFile = "test_js_client_to_py_server.log"
|
||||
$jsErrLogFile = "test_js_client_to_py_server.log.err"
|
||||
|
||||
if (Test-Path $jsLogFile) { Remove-Item $jsLogFile -Force -ErrorAction SilentlyContinue }
|
||||
if (Test-Path $jsErrLogFile) { Remove-Item $jsErrLogFile -Force -ErrorAction SilentlyContinue }
|
||||
|
||||
$jsProcess = Start-Process -FilePath "node" -ArgumentList "src/ping.js", "client", $peerInfo.MultiAddr, "3" -NoNewWindow -PassThru -RedirectStandardOutput $jsLogFile -RedirectStandardError $jsErrLogFile
|
||||
Write-ColorOutput "[DEBUG] JavaScript client PID: $($jsProcess.Id)" $Blue
|
||||
Write-ColorOutput "[DEBUG] Client logs: $((Get-Location).Path)\$jsLogFile, $((Get-Location).Path)\$jsErrLogFile" $Blue
|
||||
|
||||
# Wait for client to complete
|
||||
$clientTimeout = 10
|
||||
$clientStart = Get-Date
|
||||
while (-not $jsProcess.HasExited -and (((Get-Date) - $clientStart).TotalSeconds -lt $clientTimeout)) {
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
if (-not $jsProcess.HasExited) {
|
||||
Write-ColorOutput "[DEBUG] JavaScript client did not exit, terminating..." $Yellow
|
||||
Stop-Process -Id $jsProcess.Id -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
Write-ColorOutput "[CHECK] Results..." $Cyan
|
||||
$success = $false
|
||||
if (Test-Path $jsLogFile) {
|
||||
$jsLogContent = Get-Content $jsLogFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($jsLogContent -match "successful|Ping.*successful") {
|
||||
$success = $true
|
||||
Write-ColorOutput "[SUCCESS] Ping test passed" $Green
|
||||
} else {
|
||||
Write-ColorOutput "[FAILED] No successful pings" $Red
|
||||
Write-ColorOutput "[DEBUG] Client log path: $((Get-Location).Path)\$jsLogFile" $Yellow
|
||||
Write-ColorOutput "Client log:" $Yellow
|
||||
Write-ColorOutput $jsLogContent $Yellow
|
||||
if (Test-Path $jsErrLogFile) {
|
||||
Write-ColorOutput "[DEBUG] Client error log path: $((Get-Location).Path)\$jsErrLogFile" $Yellow
|
||||
Write-ColorOutput "Client error log:" $Yellow
|
||||
Get-Content $jsErrLogFile | Write-ColorOutput -Color $Yellow
|
||||
}
|
||||
Write-ColorOutput "[DEBUG] Python server log path: $((Get-Location).Path)\..\py_node\$pyLogFile" $Yellow
|
||||
Write-ColorOutput "Python server log:" $Yellow
|
||||
if (Test-Path "../py_node/$pyLogFile") {
|
||||
$pyLogContent = Get-Content "../py_node/$pyLogFile" -Raw -ErrorAction SilentlyContinue
|
||||
if ($pyLogContent) { Write-ColorOutput $pyLogContent $Yellow } else { Write-ColorOutput "Empty or inaccessible" $Yellow }
|
||||
} else {
|
||||
Write-ColorOutput "File not found" $Yellow
|
||||
}
|
||||
Write-ColorOutput "[DEBUG] Python server error log path: $((Get-Location).Path)\..\py_node\$pyErrLogFile" $Yellow
|
||||
Write-ColorOutput "Python server error log:" $Yellow
|
||||
if (Test-Path "../py_node/$pyErrLogFile") {
|
||||
$pyErrLogContent = Get-Content "../py_node/$pyErrLogFile" -Raw -ErrorAction SilentlyContinue
|
||||
if ($pyErrLogContent) { Write-ColorOutput $pyErrLogContent $Yellow } else { Write-ColorOutput "Empty or inaccessible" $Yellow }
|
||||
} else {
|
||||
Write-ColorOutput "File not found" $Yellow
|
||||
}
|
||||
Write-ColorOutput "[DEBUG] Python debug log path: $((Get-Location).Path)\..\py_node\$pyDebugLogFile" $Yellow
|
||||
Write-ColorOutput "Python debug log:" $Yellow
|
||||
if (Test-Path "../py_node/$pyDebugLogFile") {
|
||||
$pyDebugLogContent = Get-Content "../py_node/$pyDebugLogFile" -Raw -ErrorAction SilentlyContinue
|
||||
if ($pyDebugLogContent) { Write-ColorOutput $pyDebugLogContent $Yellow } else { Write-ColorOutput "Empty or inaccessible" $Yellow }
|
||||
} else {
|
||||
Write-ColorOutput "File not found" $Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-ColorOutput "[CLEANUP] Stopping processes..." $Yellow
|
||||
Stop-Process -Id $pyProcess.Id -Force -ErrorAction SilentlyContinue
|
||||
Stop-Process -Id $jsProcess.Id -Force -ErrorAction SilentlyContinue
|
||||
Set-Location -Path "../"
|
||||
|
||||
if ($success) {
|
||||
Write-ColorOutput "[SUCCESS] Test completed" $Green
|
||||
exit 0
|
||||
} else {
|
||||
Write-ColorOutput "[FAILED] Test failed" $Red
|
||||
exit 1
|
||||
}
|
||||
215
tests/interop/js_libp2p/scripts/run_test.sh
Normal file
215
tests/interop/js_libp2p/scripts/run_test.sh
Normal file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# run_test.sh - libp2p Interoperability Test Runner (Bash)
|
||||
# Tests py-libp2p <-> js-libp2p ping communication
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[31m'
|
||||
GREEN='\033[32m'
|
||||
YELLOW='\033[33m'
|
||||
BLUE='\033[34m'
|
||||
CYAN='\033[36m'
|
||||
RESET='\033[0m'
|
||||
|
||||
write_color_output() {
|
||||
local message="$1"
|
||||
local color="${2:-$RESET}"
|
||||
echo -e "${color}${message}${RESET}"
|
||||
}
|
||||
|
||||
write_color_output "[CHECK] Checking prerequisites..." "$CYAN"
|
||||
if ! command -v python3 &> /dev/null && ! command -v python &> /dev/null; then
|
||||
write_color_output "[ERROR] Python not found. Install Python 3.7+" "$RED"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use python3 if available, otherwise python
|
||||
PYTHON_CMD="python3"
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
PYTHON_CMD="python"
|
||||
fi
|
||||
|
||||
if ! command -v node &> /dev/null; then
|
||||
write_color_output "[ERROR] Node.js not found. Install Node.js 16+" "$RED"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
write_color_output "[CHECK] Checking port 8000..." "$BLUE"
|
||||
if netstat -tuln 2>/dev/null | grep -q ":8000 " || ss -tuln 2>/dev/null | grep -q ":8000 "; then
|
||||
write_color_output "[ERROR] Port 8000 in use. Free the port." "$RED"
|
||||
if command -v netstat &> /dev/null; then
|
||||
netstat -tuln | grep ":8000 " | write_color_output "$(cat)" "$YELLOW"
|
||||
elif command -v ss &> /dev/null; then
|
||||
ss -tuln | grep ":8000 " | write_color_output "$(cat)" "$YELLOW"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
write_color_output "[DEBUG] Cleaning up Python processes..." "$BLUE"
|
||||
pkill -f "ping.py" 2>/dev/null || true
|
||||
|
||||
write_color_output "[PYTHON] Starting server on port 8000..." "$YELLOW"
|
||||
cd py_node
|
||||
|
||||
PY_LOG_FILE="py_server_8000.log"
|
||||
PY_ERR_LOG_FILE="py_server_8000.log.err"
|
||||
PY_DEBUG_LOG_FILE="ping_debug.log"
|
||||
|
||||
rm -f "$PY_LOG_FILE" "$PY_ERR_LOG_FILE" "$PY_DEBUG_LOG_FILE"
|
||||
|
||||
$PYTHON_CMD -u ping.py server --port 8000 > "$PY_LOG_FILE" 2> "$PY_ERR_LOG_FILE" &
|
||||
PY_PROCESS_PID=$!
|
||||
|
||||
write_color_output "[DEBUG] Python server PID: $PY_PROCESS_PID" "$BLUE"
|
||||
write_color_output "[DEBUG] Python logs: $(pwd)/$PY_LOG_FILE, $(pwd)/$PY_ERR_LOG_FILE, $(pwd)/$PY_DEBUG_LOG_FILE" "$BLUE"
|
||||
|
||||
TIMEOUT_SECONDS=20
|
||||
START_TIME=$(date +%s)
|
||||
SERVER_STARTED=false
|
||||
|
||||
while [ $(($(date +%s) - START_TIME)) -lt $TIMEOUT_SECONDS ] && [ "$SERVER_STARTED" = false ]; do
|
||||
if [ -f "$PY_LOG_FILE" ]; then
|
||||
if grep -q "Server started\|Listening" "$PY_LOG_FILE" 2>/dev/null; then
|
||||
SERVER_STARTED=true
|
||||
write_color_output "[OK] Python server started" "$GREEN"
|
||||
fi
|
||||
fi
|
||||
if [ -f "$PY_ERR_LOG_FILE" ] && [ -s "$PY_ERR_LOG_FILE" ]; then
|
||||
ERR_CONTENT=$(cat "$PY_ERR_LOG_FILE" 2>/dev/null || true)
|
||||
if [ -n "$ERR_CONTENT" ]; then
|
||||
write_color_output "[DEBUG] Error log: $ERR_CONTENT" "$YELLOW"
|
||||
fi
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
|
||||
if [ "$SERVER_STARTED" = false ]; then
|
||||
write_color_output "[ERROR] Python server failed to start" "$RED"
|
||||
write_color_output "[DEBUG] Logs:" "$YELLOW"
|
||||
[ -f "$PY_LOG_FILE" ] && cat "$PY_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
[ -f "$PY_ERR_LOG_FILE" ] && cat "$PY_ERR_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
[ -f "$PY_DEBUG_LOG_FILE" ] && cat "$PY_DEBUG_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
write_color_output "[DEBUG] Trying foreground run..." "$YELLOW"
|
||||
$PYTHON_CMD -u ping.py server --port 8000
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract Peer ID
|
||||
PEER_ID=""
|
||||
MULTI_ADDR=""
|
||||
if [ -f "$PY_LOG_FILE" ]; then
|
||||
CONTENT=$(cat "$PY_LOG_FILE" 2>/dev/null || true)
|
||||
PEER_ID=$(echo "$CONTENT" | grep -oP "Peer ID:\s*\K[A-Za-z0-9]+" || true)
|
||||
if [ -n "$PEER_ID" ]; then
|
||||
MULTI_ADDR="/ip4/127.0.0.1/tcp/8000/p2p/$PEER_ID"
|
||||
write_color_output "[OK] Peer ID: $PEER_ID" "$CYAN"
|
||||
write_color_output "[OK] MultiAddr: $MULTI_ADDR" "$CYAN"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$PEER_ID" ]; then
|
||||
write_color_output "[ERROR] Could not extract Peer ID" "$RED"
|
||||
[ -f "$PY_LOG_FILE" ] && cat "$PY_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
[ -f "$PY_ERR_LOG_FILE" ] && cat "$PY_ERR_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
[ -f "$PY_DEBUG_LOG_FILE" ] && cat "$PY_DEBUG_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
kill $PY_PROCESS_PID 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start JavaScript client
|
||||
write_color_output "[JAVASCRIPT] Starting client..." "$YELLOW"
|
||||
cd ../js_node
|
||||
|
||||
JS_LOG_FILE="test_js_client_to_py_server.log"
|
||||
JS_ERR_LOG_FILE="test_js_client_to_py_server.log.err"
|
||||
|
||||
rm -f "$JS_LOG_FILE" "$JS_ERR_LOG_FILE"
|
||||
|
||||
node src/ping.js client "$MULTI_ADDR" 3 > "$JS_LOG_FILE" 2> "$JS_ERR_LOG_FILE" &
|
||||
JS_PROCESS_PID=$!
|
||||
|
||||
write_color_output "[DEBUG] JavaScript client PID: $JS_PROCESS_PID" "$BLUE"
|
||||
write_color_output "[DEBUG] Client logs: $(pwd)/$JS_LOG_FILE, $(pwd)/$JS_ERR_LOG_FILE" "$BLUE"
|
||||
|
||||
# Wait for client to complete
|
||||
CLIENT_TIMEOUT=10
|
||||
CLIENT_START=$(date +%s)
|
||||
while kill -0 $JS_PROCESS_PID 2>/dev/null && [ $(($(date +%s) - CLIENT_START)) -lt $CLIENT_TIMEOUT ]; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if kill -0 $JS_PROCESS_PID 2>/dev/null; then
|
||||
write_color_output "[DEBUG] JavaScript client did not exit, terminating..." "$YELLOW"
|
||||
kill $JS_PROCESS_PID 2>/dev/null || true
|
||||
fi
|
||||
|
||||
write_color_output "[CHECK] Results..." "$CYAN"
|
||||
SUCCESS=false
|
||||
if [ -f "$JS_LOG_FILE" ]; then
|
||||
JS_LOG_CONTENT=$(cat "$JS_LOG_FILE" 2>/dev/null || true)
|
||||
if echo "$JS_LOG_CONTENT" | grep -q "successful\|Ping.*successful"; then
|
||||
SUCCESS=true
|
||||
write_color_output "[SUCCESS] Ping test passed" "$GREEN"
|
||||
else
|
||||
write_color_output "[FAILED] No successful pings" "$RED"
|
||||
write_color_output "[DEBUG] Client log path: $(pwd)/$JS_LOG_FILE" "$YELLOW"
|
||||
write_color_output "Client log:" "$YELLOW"
|
||||
write_color_output "$JS_LOG_CONTENT" "$YELLOW"
|
||||
if [ -f "$JS_ERR_LOG_FILE" ]; then
|
||||
write_color_output "[DEBUG] Client error log path: $(pwd)/$JS_ERR_LOG_FILE" "$YELLOW"
|
||||
write_color_output "Client error log:" "$YELLOW"
|
||||
cat "$JS_ERR_LOG_FILE" | while read line; do write_color_output "$line" "$YELLOW"; done
|
||||
fi
|
||||
write_color_output "[DEBUG] Python server log path: $(pwd)/../py_node/$PY_LOG_FILE" "$YELLOW"
|
||||
write_color_output "Python server log:" "$YELLOW"
|
||||
if [ -f "../py_node/$PY_LOG_FILE" ]; then
|
||||
PY_LOG_CONTENT=$(cat "../py_node/$PY_LOG_FILE" 2>/dev/null || true)
|
||||
if [ -n "$PY_LOG_CONTENT" ]; then
|
||||
write_color_output "$PY_LOG_CONTENT" "$YELLOW"
|
||||
else
|
||||
write_color_output "Empty or inaccessible" "$YELLOW"
|
||||
fi
|
||||
else
|
||||
write_color_output "File not found" "$YELLOW"
|
||||
fi
|
||||
write_color_output "[DEBUG] Python server error log path: $(pwd)/../py_node/$PY_ERR_LOG_FILE" "$YELLOW"
|
||||
write_color_output "Python server error log:" "$YELLOW"
|
||||
if [ -f "../py_node/$PY_ERR_LOG_FILE" ]; then
|
||||
PY_ERR_LOG_CONTENT=$(cat "../py_node/$PY_ERR_LOG_FILE" 2>/dev/null || true)
|
||||
if [ -n "$PY_ERR_LOG_CONTENT" ]; then
|
||||
write_color_output "$PY_ERR_LOG_CONTENT" "$YELLOW"
|
||||
else
|
||||
write_color_output "Empty or inaccessible" "$YELLOW"
|
||||
fi
|
||||
else
|
||||
write_color_output "File not found" "$YELLOW"
|
||||
fi
|
||||
write_color_output "[DEBUG] Python debug log path: $(pwd)/../py_node/$PY_DEBUG_LOG_FILE" "$YELLOW"
|
||||
write_color_output "Python debug log:" "$YELLOW"
|
||||
if [ -f "../py_node/$PY_DEBUG_LOG_FILE" ]; then
|
||||
PY_DEBUG_LOG_CONTENT=$(cat "../py_node/$PY_DEBUG_LOG_FILE" 2>/dev/null || true)
|
||||
if [ -n "$PY_DEBUG_LOG_CONTENT" ]; then
|
||||
write_color_output "$PY_DEBUG_LOG_CONTENT" "$YELLOW"
|
||||
else
|
||||
write_color_output "Empty or inaccessible" "$YELLOW"
|
||||
fi
|
||||
else
|
||||
write_color_output "File not found" "$YELLOW"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
write_color_output "[CLEANUP] Stopping processes..." "$YELLOW"
|
||||
kill $PY_PROCESS_PID 2>/dev/null || true
|
||||
kill $JS_PROCESS_PID 2>/dev/null || true
|
||||
cd ../
|
||||
|
||||
if [ "$SUCCESS" = true ]; then
|
||||
write_color_output "[SUCCESS] Test completed" "$GREEN"
|
||||
exit 0
|
||||
else
|
||||
write_color_output "[FAILED] Test failed" "$RED"
|
||||
exit 1
|
||||
fi
|
||||
@ -1,5 +0,0 @@
|
||||
def test_js_libp2p_placeholder():
|
||||
"""
|
||||
Placeholder test for js-libp2p interop tests.
|
||||
"""
|
||||
assert True, "Placeholder test for js-libp2p interop tests"
|
||||
Reference in New Issue
Block a user