forked from Chia-Network/chia-blockchain
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_services.py
158 lines (137 loc) · 6.16 KB
/
test_services.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from __future__ import annotations
import asyncio
import signal
import sys
import time
from pathlib import Path
from typing import Any, Dict
import aiohttp.client_exceptions
import pytest
from typing_extensions import Protocol
from chia.daemon.client import DaemonProxy, connect_to_daemon_and_validate
from chia.rpc.data_layer_rpc_client import DataLayerRpcClient
from chia.rpc.farmer_rpc_client import FarmerRpcClient
from chia.rpc.full_node_rpc_client import FullNodeRpcClient
from chia.rpc.harvester_rpc_client import HarvesterRpcClient
from chia.rpc.rpc_client import RpcClient
from chia.rpc.wallet_rpc_client import WalletRpcClient
from chia.simulator.socket import find_available_listen_port
from chia.simulator.time_out_assert import adjusted_timeout
from chia.util.config import lock_and_load_config, save_config
from chia.util.ints import uint16
from chia.util.misc import sendable_termination_signals
from tests.core.data_layer.util import ChiaRoot
from tests.util.misc import closing_chia_root_popen
class CreateServiceProtocol(Protocol):
async def __call__(
self,
self_hostname: str,
port: uint16,
root_path: Path,
net_config: Dict[str, Any],
) -> RpcClient:
...
async def wait_for_daemon_connection(root_path: Path, config: Dict[str, Any], timeout: float = 15) -> DaemonProxy:
timeout = adjusted_timeout(timeout=timeout)
start = time.monotonic()
while time.monotonic() - start < timeout:
client = await connect_to_daemon_and_validate(root_path=root_path, config=config, quiet=True)
if client is not None:
break
await asyncio.sleep(0.1)
else:
raise Exception(f"unable to connect within {timeout} seconds")
return client
@pytest.mark.parametrize(argnames="signal_number", argvalues=sendable_termination_signals)
@pytest.mark.asyncio
async def test_daemon_terminates(signal_number: signal.Signals, chia_root: ChiaRoot) -> None:
port = find_available_listen_port()
with lock_and_load_config(root_path=chia_root.path, filename="config.yaml") as config:
config["daemon_port"] = port
save_config(root_path=chia_root.path, filename="config.yaml", config_data=config)
with closing_chia_root_popen(chia_root=chia_root, args=[sys.executable, "-m", "chia.daemon.server"]) as process:
client = await wait_for_daemon_connection(root_path=chia_root.path, config=config)
try:
return_code = process.poll()
assert return_code is None
process.send_signal(signal_number)
process.communicate(timeout=adjusted_timeout(timeout=5))
finally:
await client.close()
@pytest.mark.parametrize(argnames="signal_number", argvalues=sendable_termination_signals)
@pytest.mark.parametrize(
argnames=["create_service", "module_path", "service_config_name"],
argvalues=[
[DataLayerRpcClient.create, "chia.server.start_data_layer", "data_layer"],
[FarmerRpcClient.create, "chia.server.start_farmer", "farmer"],
[FullNodeRpcClient.create, "chia.server.start_full_node", "full_node"],
[HarvesterRpcClient.create, "chia.server.start_harvester", "harvester"],
[WalletRpcClient.create, "chia.server.start_wallet", "wallet"],
# TODO: review and somehow test the other services too
# [, "chia.server.start_introducer", "introducer"],
# [, "chia.seeder.start_crawler", ""],
# [, "chia.server.start_timelord", "timelord"],
# [, "chia.timelord.timelord_launcher", ],
# [, "chia.simulator.start_simulator", ],
# [, "chia.data_layer.data_layer_server", "data_layer"],
],
)
@pytest.mark.asyncio
async def test_services_terminate(
signal_number: signal.Signals,
chia_root: ChiaRoot,
create_service: CreateServiceProtocol,
module_path: str,
service_config_name: str,
) -> None:
with lock_and_load_config(root_path=chia_root.path, filename="config.yaml") as config:
config["daemon_port"] = find_available_listen_port(name="daemon")
service_config = config[service_config_name]
if "port" in service_config:
port = find_available_listen_port(name="service")
service_config["port"] = port
rpc_port = find_available_listen_port(name="rpc")
service_config["rpc_port"] = rpc_port
save_config(root_path=chia_root.path, filename="config.yaml", config_data=config)
# TODO: make the wallet start up regardless so this isn't needed
with closing_chia_root_popen(
chia_root=chia_root,
args=[sys.executable, "-m", "chia.daemon.server"],
):
# Make sure the daemon is running and responsive before starting other services.
# This probably shouldn't be required. For now, it helps at least with the
# farmer.
daemon_client = await wait_for_daemon_connection(root_path=chia_root.path, config=config)
await daemon_client.close()
with closing_chia_root_popen(
chia_root=chia_root,
args=[sys.executable, "-m", module_path],
) as process:
client = await create_service(
self_hostname=config["self_hostname"],
port=uint16(rpc_port),
root_path=chia_root.path,
net_config=config,
)
try:
start = time.monotonic()
while time.monotonic() - start < 50:
return_code = process.poll()
assert return_code is None
try:
result = await client.healthz()
except aiohttp.client_exceptions.ClientConnectorError:
pass
else:
if result.get("success", False):
break
await asyncio.sleep(0.1)
else:
raise Exception("unable to connect")
return_code = process.poll()
assert return_code is None
process.send_signal(signal_number)
process.communicate(timeout=adjusted_timeout(timeout=30))
finally:
client.close()
await client.await_closed()