mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
* fix pyproject.toml , add ruff * rm lock * make progress * add poetry lock ignore * fix type issues * fix tcp type errors * fix text example - type error - wrong args * add setuptools to dev * test ci * fix docs build * fix type issues for new_swarm & new_host * fix types in gossipsub * fix type issues in noise * wip: factories * revert factories * fix more type issues * more type fixes * fix: add null checks for noise protocol initialization and key handling * corrected argument-errors in peerId and Multiaddr in peer tests * fix: Noice - remove redundant type casts in BaseNoiseMsgReadWriter * fix: update test_notify.py to use SwarmFactory.create_batch_and_listen, fix type hints, and comment out ClosedStream assertions * Fix type checks for pubsub module Signed-off-by: sukhman <sukhmansinghsaluja@gmail.com> * Fix type checks for pubsub module-tests Signed-off-by: sukhman <sukhmansinghsaluja@gmail.com> * noise: add checks for uninitialized protocol and key states in PatternXX Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> * pubsub: add None checks for optional fields in FloodSub and Pubsub Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> * Fix type hints and improve testing Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> * remove redundant checks Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> * fix build issues * add optional to trio service * fix types * fix type errors * Fix type errors Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> * fixed more-type checks in crypto and peer_data files * wip: factories * replaced union with optional * fix: type-error in interp-utils and peerinfo * replace pyright with pyrefly * add pyrefly.toml * wip: fix multiselect issues * try typecheck * base check * mcache test fixes , typecheck ci update * fix ci * will this work * minor fix * use poetry * fix wokflow * use cache,fix err * fix pyrefly.toml * fix pyrefly.toml * fix cache in ci * deploy commit * add main baseline * update to v5 * improve typecheck ci (#14) * fix typo * remove holepunching code (#16) * fix gossipsub typeerrors (#17) * fix: ensure initiator user includes remote peer id in handshake (#15) * fix ci (#19) * typefix: custom_types | core/peerinfo/test_peer_info | io/abc | pubsub/floodsub | protocol_muxer/multiselect (#18) * fix: Typefixes in PeerInfo (#21) * fix minor type issue (#22) * fix type errors in pubsub (#24) * fix: Minor typefixes in tests (#23) * Fix failing tests for type-fixed test/pubsub (#8) * move pyrefly & ruff to pyproject.toml & rm .project-template (#28) * move the async_context file to tests/core * move crypto test to crypto folder * fix: some typefixes (#25) * fix type errors * fix type issues * fix: update gRPC API usage in autonat_pb2_grpc.py (#31) * md: typecheck ci * rm comments * clean up : from review suggestions * use | None over Optional as per new python standards * drop supporto for py3.9 * newsfragments --------- Signed-off-by: sukhman <sukhmansinghsaluja@gmail.com> Signed-off-by: varun-r-mallya <varunrmallya@gmail.com> Co-authored-by: acul71 <luca.pisani@birdo.net> Co-authored-by: kaneki003 <sakshamchauhan707@gmail.com> Co-authored-by: sukhman <sukhmansinghsaluja@gmail.com> Co-authored-by: varun-r-mallya <varunrmallya@gmail.com> Co-authored-by: varunrmallya <100590632+varun-r-mallya@users.noreply.github.com> Co-authored-by: lla-dane <abhinavagarwalla6@gmail.com> Co-authored-by: Collins <ArtemisfowlX@protonmail.com> Co-authored-by: Abhinav Agarwalla <120122716+lla-dane@users.noreply.github.com> Co-authored-by: guha-rahul <52607971+guha-rahul@users.noreply.github.com> Co-authored-by: Sukhman Singh <63765293+sukhman-sukh@users.noreply.github.com> Co-authored-by: acul71 <34693171+acul71@users.noreply.github.com> Co-authored-by: pacrob <5199899+pacrob@users.noreply.github.com>
241 lines
7.7 KiB
Python
241 lines
7.7 KiB
Python
from unittest.mock import (
|
|
AsyncMock,
|
|
patch,
|
|
)
|
|
|
|
import pytest
|
|
|
|
from libp2p.host.autonat.autonat import (
|
|
AUTONAT_PROTOCOL_ID,
|
|
AutoNATService,
|
|
AutoNATStatus,
|
|
)
|
|
from libp2p.host.autonat.pb.autonat_pb2 import (
|
|
DialRequest,
|
|
DialResponse,
|
|
Message,
|
|
PeerInfo,
|
|
Status,
|
|
Type,
|
|
)
|
|
from libp2p.network.stream.exceptions import (
|
|
StreamError,
|
|
)
|
|
from libp2p.network.stream.net_stream import (
|
|
NetStream,
|
|
)
|
|
from libp2p.peer.id import (
|
|
ID,
|
|
)
|
|
from tests.utils.factories import (
|
|
HostFactory,
|
|
)
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_autonat_service_initialization():
|
|
"""Test that the AutoNAT service initializes correctly."""
|
|
async with HostFactory.create_batch_and_listen(1) as hosts:
|
|
host = hosts[0]
|
|
service = AutoNATService(host)
|
|
|
|
assert service.status == AutoNATStatus.UNKNOWN
|
|
assert service.dial_results == {}
|
|
assert service.host == host
|
|
assert service.peerstore == host.get_peerstore()
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_autonat_status_getter():
|
|
"""Test that the AutoNAT status getter works correctly."""
|
|
async with HostFactory.create_batch_and_listen(1) as hosts:
|
|
host = hosts[0]
|
|
service = AutoNATService(host)
|
|
|
|
# Testing the initial status
|
|
assert service.get_status() == AutoNATStatus.UNKNOWN
|
|
|
|
# Testing the status changes
|
|
service.status = AutoNATStatus.PUBLIC
|
|
assert service.get_status() == AutoNATStatus.PUBLIC
|
|
|
|
service.status = AutoNATStatus.PRIVATE
|
|
assert service.get_status() == AutoNATStatus.PRIVATE
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_update_status():
|
|
"""Test that the AutoNAT status updates correctly based on dial results."""
|
|
async with HostFactory.create_batch_and_listen(1) as hosts:
|
|
host = hosts[0]
|
|
service = AutoNATService(host)
|
|
|
|
# No dial results should result in UNKNOWN status
|
|
service.update_status()
|
|
assert service.status == AutoNATStatus.UNKNOWN
|
|
|
|
# Less than 2 successful dials should result in PRIVATE status
|
|
service.dial_results = {
|
|
ID(b"peer1"): True,
|
|
ID(b"peer2"): False,
|
|
ID(b"peer3"): False,
|
|
}
|
|
service.update_status()
|
|
assert service.status == AutoNATStatus.PRIVATE
|
|
|
|
# 2 or more successful dials should result in PUBLIC status
|
|
service.dial_results = {
|
|
ID(b"peer1"): True,
|
|
ID(b"peer2"): True,
|
|
ID(b"peer3"): False,
|
|
}
|
|
service.update_status()
|
|
assert service.status == AutoNATStatus.PUBLIC
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_try_dial():
|
|
"""Test that the try_dial method works correctly."""
|
|
async with HostFactory.create_batch_and_listen(2) as hosts:
|
|
host1, host2 = hosts
|
|
service = AutoNATService(host1)
|
|
peer_id = host2.get_id()
|
|
|
|
# Test successful dial
|
|
with patch.object(
|
|
host1, "new_stream", new_callable=AsyncMock
|
|
) as mock_new_stream:
|
|
mock_stream = AsyncMock(spec=NetStream)
|
|
mock_new_stream.return_value = mock_stream
|
|
|
|
result = await service._try_dial(peer_id)
|
|
|
|
assert result is True
|
|
mock_new_stream.assert_called_once_with(peer_id, [AUTONAT_PROTOCOL_ID])
|
|
mock_stream.close.assert_called_once()
|
|
|
|
# Test failed dial
|
|
with patch.object(
|
|
host1, "new_stream", new_callable=AsyncMock
|
|
) as mock_new_stream:
|
|
mock_new_stream.side_effect = Exception("Connection failed")
|
|
|
|
result = await service._try_dial(peer_id)
|
|
|
|
assert result is False
|
|
mock_new_stream.assert_called_once_with(peer_id, [AUTONAT_PROTOCOL_ID])
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_handle_dial():
|
|
"""Test that the handle_dial method works correctly."""
|
|
async with HostFactory.create_batch_and_listen(2) as hosts:
|
|
host1, host2 = hosts
|
|
service = AutoNATService(host1)
|
|
peer_id = host2.get_id()
|
|
|
|
# Create a mock message with a peer to dial
|
|
message = Message()
|
|
message.type = Type.Value("DIAL")
|
|
peer_info = PeerInfo()
|
|
peer_info.id = peer_id.to_bytes()
|
|
peer_info.addrs.extend([b"/ip4/127.0.0.1/tcp/4001"])
|
|
message.dial.peers.append(peer_info)
|
|
|
|
# Mock the _try_dial method
|
|
with patch.object(
|
|
service, "_try_dial", new_callable=AsyncMock
|
|
) as mock_try_dial:
|
|
mock_try_dial.return_value = True
|
|
|
|
response = await service._handle_dial(message)
|
|
|
|
assert response.type == Type.Value("DIAL_RESPONSE")
|
|
assert response.dial_response.status == Status.OK
|
|
assert len(response.dial_response.peers) == 1
|
|
assert response.dial_response.peers[0].id == peer_id.to_bytes()
|
|
assert response.dial_response.peers[0].success is True
|
|
mock_try_dial.assert_called_once_with(peer_id)
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_handle_request():
|
|
"""Test that the handle_request method works correctly."""
|
|
async with HostFactory.create_batch_and_listen(1) as hosts:
|
|
host = hosts[0]
|
|
service = AutoNATService(host)
|
|
|
|
# Test handling a DIAL request
|
|
message = Message()
|
|
message.type = Type.DIAL
|
|
dial_request = DialRequest()
|
|
peer_info = PeerInfo()
|
|
dial_request.peers.append(peer_info)
|
|
message.dial.CopyFrom(dial_request)
|
|
|
|
with patch.object(
|
|
service, "_handle_dial", new_callable=AsyncMock
|
|
) as mock_handle_dial:
|
|
mock_handle_dial.return_value = Message()
|
|
|
|
response = await service._handle_request(message.SerializeToString())
|
|
|
|
mock_handle_dial.assert_called_once()
|
|
assert isinstance(response, Message)
|
|
|
|
# Test handling an unknown request type
|
|
message = Message()
|
|
message.type = Type.UNKNOWN
|
|
|
|
response = await service._handle_request(message.SerializeToString())
|
|
|
|
assert isinstance(response, Message)
|
|
assert response.type == Type.DIAL_RESPONSE
|
|
assert response.dial_response.status == Status.E_INTERNAL_ERROR
|
|
|
|
|
|
@pytest.mark.trio
|
|
async def test_handle_stream():
|
|
"""Test that handle_stream correctly processes stream data."""
|
|
async with HostFactory.create_batch_and_listen(1) as hosts:
|
|
host = hosts[0]
|
|
autonat_service = AutoNATService(host)
|
|
|
|
# Create a mock stream
|
|
mock_stream = AsyncMock(spec=NetStream)
|
|
|
|
# Create a properly initialized request Message
|
|
request = Message()
|
|
request.type = Type.DIAL
|
|
dial_request = DialRequest()
|
|
peer_info = PeerInfo()
|
|
peer_info.id = b"peer_id"
|
|
peer_info.addrs.append(b"addr1")
|
|
dial_request.peers.append(peer_info)
|
|
request.dial.CopyFrom(dial_request)
|
|
|
|
# Create a properly initialized response Message
|
|
response = Message()
|
|
response.type = Type.DIAL_RESPONSE
|
|
dial_response = DialResponse()
|
|
dial_response.status = Status.OK
|
|
dial_response.peers.append(peer_info)
|
|
response.dial_response.CopyFrom(dial_response)
|
|
|
|
# Mock stream read/write and _handle_request
|
|
mock_stream.read.return_value = request.SerializeToString()
|
|
mock_stream.write.return_value = None
|
|
autonat_service._handle_request = AsyncMock(return_value=response)
|
|
|
|
# Test successful stream handling
|
|
await autonat_service.handle_stream(mock_stream)
|
|
mock_stream.read.assert_called_once()
|
|
mock_stream.write.assert_called_once_with(response.SerializeToString())
|
|
mock_stream.close.assert_called_once()
|
|
|
|
# Test stream error handling
|
|
mock_stream.reset_mock()
|
|
mock_stream.read.side_effect = StreamError("Stream error")
|
|
await autonat_service.handle_stream(mock_stream)
|
|
mock_stream.close.assert_called_once()
|