Skip to content

Commit 5db5bd2

Browse files
author
Roman
committed
update test's runners
1 parent 7061f65 commit 5db5bd2

File tree

4 files changed

+146
-31
lines changed

4 files changed

+146
-31
lines changed

tests/e2e_tests/conftest.py

Lines changed: 142 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import shutil
66
import signal
77
import subprocess
8+
import sys
89
import time
910

1011
import pytest
@@ -13,9 +14,48 @@
1314
from .utils import setup_wallet
1415

1516

17+
def wait_for_node_start(process, pattern, timestamp: int = None):
18+
for line in process.stdout:
19+
print(line.strip())
20+
# 20 min as timeout
21+
timestamp = timestamp or int(time.time())
22+
if int(time.time()) - timestamp > 20 * 60:
23+
pytest.fail("Subtensor not started in time")
24+
if pattern.search(line):
25+
print("Node started!")
26+
break
27+
28+
1629
# Fixture for setting up and tearing down a localnet.sh chain between tests
1730
@pytest.fixture(scope="function")
1831
def local_chain(request):
32+
"""Determines whether to run the localnet.sh script in a subprocess or a Docker container."""
33+
args = request.param if hasattr(request, "param") else None
34+
params = "" if args is None else f"{args}"
35+
if shutil.which("docker") and not os.getenv("USE_DOCKER") == "0":
36+
yield from docker_runner(params)
37+
else:
38+
if not os.getenv("USE_DOCKER") == "0":
39+
if sys.platform.startswith("linux"):
40+
docker_command = (
41+
"Install docker with command "
42+
"[blue]sudo apt-get update && sudo apt-get install docker.io -y[/blue]"
43+
" or use documentation [blue]https://docs.docker.com/engine/install/[/blue]"
44+
)
45+
elif sys.platform == "darwin":
46+
docker_command = (
47+
"Install docker with command [blue]brew install docker[/blue]"
48+
)
49+
else:
50+
docker_command = "[blue]Unknown OS, install Docker manually: https://docs.docker.com/get-docker/[/blue]"
51+
52+
logging.warning("Docker not found in the operating system!")
53+
logging.warning(docker_command)
54+
logging.warning("Tests are run in legacy mode.")
55+
yield from legacy_runner(request)
56+
57+
58+
def legacy_runner(request):
1959
param = request.param if hasattr(request, "param") else None
2060
# Get the environment variable for the script path
2161
script_path = os.getenv("LOCALNET_SH_PATH")
@@ -41,18 +81,6 @@ def local_chain(request):
4181
# Install neuron templates
4282
logging.info("Downloading and installing neuron templates from github")
4383

44-
timestamp = int(time.time())
45-
46-
def wait_for_node_start(process, pattern):
47-
for line in process.stdout:
48-
print(line.strip())
49-
# 20 min as timeout
50-
if int(time.time()) - timestamp > 20 * 60:
51-
pytest.fail("Subtensor not started in time")
52-
if pattern.search(line):
53-
print("Node started!")
54-
break
55-
5684
wait_for_node_start(process, pattern)
5785

5886
# Run the test, passing in substrate interface
@@ -72,6 +100,108 @@ def wait_for_node_start(process, pattern):
72100
process.wait()
73101

74102

103+
def docker_runner(params):
104+
"""Starts a Docker container before tests and gracefully terminates it after."""
105+
106+
def is_docker_running():
107+
"""Check if Docker has been run."""
108+
try:
109+
subprocess.run(
110+
["docker", "info"],
111+
stdout=subprocess.DEVNULL,
112+
stderr=subprocess.DEVNULL,
113+
check=True,
114+
)
115+
return True
116+
except subprocess.CalledProcessError:
117+
return False
118+
119+
def try_start_docker():
120+
"""Run docker based on OS."""
121+
try:
122+
subprocess.run(["open", "-a", "Docker"], check=True) # macOS
123+
except (FileNotFoundError, subprocess.CalledProcessError):
124+
try:
125+
subprocess.run(["systemctl", "start", "docker"], check=True) # Linux
126+
except (FileNotFoundError, subprocess.CalledProcessError):
127+
try:
128+
subprocess.run(
129+
["sudo", "service", "docker", "start"], check=True
130+
) # Linux alternative
131+
except (FileNotFoundError, subprocess.CalledProcessError):
132+
print("Failed to start Docker. Manual start may be required.")
133+
return False
134+
135+
# Wait Docker run 10 attempts with 3 sec waits
136+
for _ in range(10):
137+
if is_docker_running():
138+
return True
139+
time.sleep(3)
140+
141+
print("Docker wasn't run. Manual start may be required.")
142+
return False
143+
144+
container_name = f"test_local_chain_{str(time.time()).replace('.', '_')}"
145+
image_name = "ghcr.io/opentensor/subtensor-localnet:latest"
146+
147+
# Command to start container
148+
cmds = [
149+
"docker",
150+
"run",
151+
"--rm",
152+
"--name",
153+
container_name,
154+
"-p",
155+
"9944:9944",
156+
"-p",
157+
"9945:9945",
158+
image_name,
159+
params,
160+
]
161+
162+
try_start_docker()
163+
164+
# Start container
165+
with subprocess.Popen(
166+
cmds,
167+
stdout=subprocess.PIPE,
168+
stderr=subprocess.PIPE,
169+
text=True,
170+
start_new_session=True,
171+
) as process:
172+
try:
173+
substrate = None
174+
try:
175+
pattern = re.compile(r"Imported #1")
176+
wait_for_node_start(process, pattern, int(time.time()))
177+
except TimeoutError:
178+
raise
179+
180+
result = subprocess.run(
181+
["docker", "ps", "-q", "-f", f"name={container_name}"],
182+
capture_output=True,
183+
text=True,
184+
)
185+
if not result.stdout.strip():
186+
raise RuntimeError("Docker container failed to start.")
187+
188+
substrate = AsyncSubstrateInterface(url="ws://127.0.0.1:9944")
189+
yield substrate
190+
191+
finally:
192+
try:
193+
if substrate:
194+
substrate.close()
195+
except Exception:
196+
pass
197+
198+
try:
199+
subprocess.run(["docker", "kill", container_name])
200+
process.wait()
201+
except subprocess.TimeoutExpired:
202+
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
203+
204+
75205
@pytest.fixture(scope="function")
76206
def wallet_setup():
77207
wallet_paths = []

tests/e2e_tests/test_senate.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,17 +216,17 @@ def test_senate(local_chain, wallet_setup):
216216
proposals_after_nay_output = proposals_after_nay.stdout.splitlines()
217217

218218
# Total Ayes to remain 1
219-
proposals_after_nay_output[9].split()[2] == "1"
219+
assert proposals_after_nay_output[9].split()[2] == "1"
220220

221221
# Total Nays increased to 1
222-
proposals_after_nay_output[9].split()[4] == "1"
222+
assert proposals_after_nay_output[9].split()[4] == "1"
223223

224224
# Assert Alice has voted Nay
225-
proposals_after_nay_output[10].split()[0].strip(
225+
assert proposals_after_nay_output[10].split()[0].strip(
226226
":"
227227
) == wallet_alice.hotkey.ss58_address
228228

229229
# Assert vote casted as Nay
230-
proposals_after_nay_output[9].split()[1] == "Nay"
230+
assert proposals_after_nay_output[9].split()[1] == "Nay"
231231

232232
print("✅ Passed senate commands")

tests/e2e_tests/test_staking_sudo.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import re
2-
import time
32

43
from bittensor_cli.src.bittensor.balances import Balance
54

tests/e2e_tests/test_wallet_creations.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -486,20 +486,6 @@ def test_wallet_balance_all(local_chain, wallet_setup, capfd):
486486
wallet_name = f"test_wallet_{i}"
487487
wallet_names.append(wallet_name)
488488

489-
result = exec_command(
490-
command="wallet",
491-
sub_command="new-coldkey",
492-
extra_args=[
493-
"--wallet-name",
494-
wallet_name,
495-
"--wallet-path",
496-
wallet_path,
497-
"--n-words",
498-
"12",
499-
"--no-use-password",
500-
],
501-
)
502-
503489
wallet_status, message = verify_wallet_dir(wallet_path, wallet_name)
504490
assert wallet_status, message
505491

0 commit comments

Comments
 (0)