Skip to content

Commit 78029ce

Browse files
authored
Merge pull request #110 from voyager1708/restore-tests-and-peer-bak
Restore tests
2 parents 0118da6 + 7c9961c commit 78029ce

File tree

106 files changed

+15642
-8
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+15642
-8
lines changed

tests/bsv/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

tests/bsv/auth/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

tests/bsv/auth/clients/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import pytest
2+
from unittest.mock import AsyncMock, MagicMock
3+
from bsv.auth.clients.auth_fetch import AuthFetch, SimplifiedFetchRequestOptions
4+
from bsv.auth.requested_certificate_set import RequestedCertificateSet
5+
from bsv.auth.auth_message import AuthMessage
6+
from bsv.auth.peer import Peer, PeerOptions
7+
8+
9+
class DummyWallet:
10+
def get_public_key(self, ctx, args, originator):
11+
return {"publicKey": "02a1633c...", "derivationPrefix": "m/0"}
12+
13+
def create_action(self, ctx, args, originator):
14+
return {"tx": "0100000001abcdef..."}
15+
16+
def create_signature(self, ctx, args, originator):
17+
return {"signature": b"dummy_signature"}
18+
19+
def verify_signature(self, ctx, args, originator):
20+
return {"valid": True}
21+
22+
23+
@pytest.mark.asyncio
24+
async def test_fetch_basic_request():
25+
wallet = DummyWallet()
26+
requested_certs = RequestedCertificateSet()
27+
auth_fetch = AuthFetch(wallet, requested_certs)
28+
url = "https://example.com/api"
29+
config = SimplifiedFetchRequestOptions(method="GET", headers={"Accept": "application/json"})
30+
31+
# モックのPeerとTransport
32+
mock_transport = MagicMock()
33+
mock_transport.send = AsyncMock(return_value=None)
34+
mock_transport.on_data = MagicMock(return_value=None)
35+
peer_options = PeerOptions(wallet=wallet, transport=mock_transport, certificates_to_request=requested_certs)
36+
mock_peer = Peer(peer_options)
37+
mock_peer.get_authenticated_session = AsyncMock(return_value=MagicMock(peer_nonce="dummy", is_authenticated=True, peer_identity_key="dummy"))
38+
mock_peer.to_peer = MagicMock(return_value=None) # 同期メソッドとしてモック
39+
mock_peer.listen_for_general_messages = MagicMock(return_value=1)
40+
mock_peer.stop_listening_for_general_messages = MagicMock()
41+
42+
# peersにセット
43+
auth_peer = auth_fetch.peers["https://example.com"] = MagicMock()
44+
auth_peer.peer = mock_peer
45+
46+
auth_fetch.fetch(None, url, config)
47+
mock_peer.to_peer.assert_called_once()
48+
49+
@pytest.mark.asyncio
50+
async def test_fetch_with_auth_headers():
51+
wallet = DummyWallet()
52+
requested_certs = RequestedCertificateSet()
53+
auth_fetch = AuthFetch(wallet, requested_certs)
54+
url = "https://example.com/api"
55+
config = SimplifiedFetchRequestOptions(
56+
method="POST",
57+
headers={"Content-Type": "application/json", "X-Auth-Required": "true"},
58+
body=b'{"test": "data"}'
59+
)
60+
mock_transport = MagicMock()
61+
mock_transport.send = AsyncMock(return_value=None)
62+
mock_transport.on_data = MagicMock(return_value=None)
63+
peer_options = PeerOptions(wallet=wallet, transport=mock_transport, certificates_to_request=requested_certs)
64+
mock_peer = Peer(peer_options)
65+
mock_peer.get_authenticated_session = AsyncMock(return_value=MagicMock(peer_nonce="dummy", is_authenticated=True, peer_identity_key="dummy"))
66+
mock_peer.to_peer = MagicMock(return_value=None) # 同期メソッドとしてモック
67+
mock_peer.listen_for_general_messages = MagicMock(return_value=1)
68+
mock_peer.stop_listening_for_general_messages = MagicMock()
69+
auth_peer = auth_fetch.peers["https://example.com"] = MagicMock()
70+
auth_peer.peer = mock_peer
71+
auth_fetch.fetch(None, url, config)
72+
mock_peer.to_peer.assert_called_once()
73+
74+
@pytest.mark.asyncio
75+
async def test_fetch_error_handling():
76+
wallet = DummyWallet()
77+
requested_certs = RequestedCertificateSet()
78+
auth_fetch = AuthFetch(wallet, requested_certs)
79+
url = "https://example.com/api"
80+
config = SimplifiedFetchRequestOptions(method="GET")
81+
mock_transport = MagicMock()
82+
mock_transport.send = AsyncMock(side_effect=Exception("Network error"))
83+
mock_transport.on_data = MagicMock(return_value=None)
84+
peer_options = PeerOptions(wallet=wallet, transport=mock_transport, certificates_to_request=requested_certs)
85+
mock_peer = Peer(peer_options)
86+
mock_peer.get_authenticated_session = AsyncMock(return_value=MagicMock(peer_nonce="dummy", is_authenticated=True, peer_identity_key="dummy"))
87+
mock_peer.to_peer = MagicMock(side_effect=Exception("Network error")) # 同期メソッドとして例外
88+
mock_peer.listen_for_general_messages = MagicMock(return_value=1)
89+
mock_peer.stop_listening_for_general_messages = MagicMock()
90+
auth_peer = auth_fetch.peers["https://example.com"] = MagicMock()
91+
auth_peer.peer = mock_peer
92+
with pytest.raises(RuntimeError, match="Network error"):
93+
auth_fetch.fetch(None, url, config)
94+
95+
def test_consume_received_certificates():
96+
wallet = DummyWallet()
97+
requested_certs = RequestedCertificateSet()
98+
auth_fetch = AuthFetch(wallet, requested_certs)
99+
mock_cert = {"type": "authrite", "validationKey": "test_key", "serialNumber": "123", "validFrom": 1000, "validUntil": 2000}
100+
auth_fetch.certificates_received = [mock_cert]
101+
certs = auth_fetch.consume_received_certificates()
102+
assert len(certs) == 1
103+
assert certs[0]["type"] == "authrite"
104+
assert certs[0]["serialNumber"] == "123"
105+
assert len(auth_fetch.certificates_received) == 0
106+
107+
def test_validate_request_options():
108+
config = SimplifiedFetchRequestOptions()
109+
assert config.method == "GET"
110+
assert isinstance(config.headers, dict)
111+
assert config.body is None
112+
assert config.retry_counter is None
113+
config = SimplifiedFetchRequestOptions(method="POST")
114+
assert config.method == "POST"
115+
config = SimplifiedFetchRequestOptions(headers={"X-Test": "value"})
116+
assert config.headers["X-Test"] == "value"
117+
config = SimplifiedFetchRequestOptions(body=b"test")
118+
assert config.body == b"test"
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
import json
3+
from aiohttp import web
4+
from bsv.auth.clients.auth_fetch import AuthFetch, SimplifiedFetchRequestOptions
5+
from bsv.auth.requested_certificate_set import RequestedCertificateSet
6+
from bsv.auth.peer import PeerOptions
7+
import asyncio
8+
9+
class DummyWallet:
10+
def get_public_key(self, ctx, args, originator):
11+
return {"publicKey": "02a1633c...", "derivationPrefix": "m/0"}
12+
def create_action(self, ctx, args, originator):
13+
return {"tx": "0100000001abcdef..."}
14+
def create_signature(self, ctx, args, originator):
15+
return {"signature": b"dummy_signature"}
16+
def verify_signature(self, ctx, args, originator):
17+
return {"valid": True}
18+
19+
import json
20+
import pytest
21+
from aiohttp import web
22+
23+
import pytest_asyncio
24+
25+
@pytest_asyncio.fixture
26+
async def auth_server(unused_tcp_port):
27+
async def handle_authfetch(request):
28+
print("[auth_server] /authfetch called")
29+
body = await request.json()
30+
print(f"[auth_server] received body: {body}")
31+
# emulate processing delay so the test actually waits
32+
await asyncio.sleep(0.3)
33+
# 最小応答(initialRequestに対するinitialResponse)
34+
resp = {
35+
"message_type": "initialResponse",
36+
"server_nonce": "c2VydmVyX25vbmNl",
37+
}
38+
print(f"[auth_server] sending: {resp}")
39+
return web.json_response(resp)
40+
41+
app = web.Application()
42+
app.router.add_post("/authfetch", handle_authfetch)
43+
runner = web.AppRunner(app)
44+
await runner.setup()
45+
port = unused_tcp_port
46+
site = web.TCPSite(runner, "127.0.0.1", port)
47+
await site.start()
48+
try:
49+
yield f"http://127.0.0.1:{port}"
50+
finally:
51+
await runner.cleanup()
52+
53+
@pytest.mark.asyncio
54+
async def test_authfetch_e2e(auth_server):
55+
wallet = DummyWallet()
56+
requested_certs = RequestedCertificateSet()
57+
auth_fetch = AuthFetch(wallet, requested_certs)
58+
59+
from bsv.auth.clients.auth_fetch import AuthPeer
60+
61+
base = auth_server.rstrip("/")
62+
# 既存のキーを消してから、フォールバック指定のPeerを登録
63+
auth_fetch.peers.pop(base, None)
64+
ap = AuthPeer()
65+
ap.supports_mutual_auth = False # ← 有効化
66+
auth_fetch.peers[base] = ap
67+
68+
headers = {"Content-Type": "application/json"}
69+
config = SimplifiedFetchRequestOptions(
70+
method="POST",
71+
headers=headers,
72+
body=b'{"message_type":"initialRequest","initial_nonce":"dGVzdF9ub25jZQ==","identity_key":"test_client_key"}'
73+
)
74+
print(f"[test] calling fetch to {base}/authfetch")
75+
resp = await asyncio.wait_for(
76+
asyncio.to_thread(auth_fetch.fetch, None, f"{base}/authfetch", config),
77+
timeout=10,
78+
)
79+
print(f"[test] got response: status={getattr(resp,'status_code',None)} text={getattr(resp,'text',None)}")
80+
assert resp is not None and resp.status_code == 200
81+
data = json.loads(resp.text)
82+
assert data.get("message_type") == "initialResponse"

0 commit comments

Comments
 (0)