mirror of
https://github.com/0glabs/0g-storage-node.git
synced 2024-12-25 07:45:17 +00:00
Fix python test (#8)
* Fix stdouterr issue when shutdown storage node * Fix random failure for submission test * add more info for failed rpc * use single file instead of subprocess pipe to launch CLI * Opt test_all for windows * wait for log entry before file sync by admin
This commit is contained in:
parent
7479f56474
commit
8b225fde43
@ -84,6 +84,7 @@ class CliSubmissionTest(TestFramework):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
self.log.info("wait node %d", i)
|
self.log.info("wait node %d", i)
|
||||||
|
wait_until(lambda: self.nodes[i].zgs_get_file_info(root) is not None)
|
||||||
self.nodes[i].admin_start_sync_file(submission_index - 1)
|
self.nodes[i].admin_start_sync_file(submission_index - 1)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
||||||
@ -91,7 +92,6 @@ class CliSubmissionTest(TestFramework):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
wait_until(lambda: self.nodes[i].zgs_get_file_info(root) is not None)
|
|
||||||
wait_until(lambda: self.nodes[i].zgs_get_file_info(root)["finalized"])
|
wait_until(lambda: self.nodes[i].zgs_get_file_info(root)["finalized"])
|
||||||
|
|
||||||
# start_idx = random.randint(0, num_of_entris - 1)
|
# start_idx = random.randint(0, num_of_entris - 1)
|
||||||
|
@ -22,11 +22,11 @@ class CrashTest(TestFramework):
|
|||||||
self.log.info("segment: %s", segment)
|
self.log.info("segment: %s", segment)
|
||||||
|
|
||||||
for i in range(self.num_nodes):
|
for i in range(self.num_nodes):
|
||||||
self.nodes[i].admin_start_sync_file(0)
|
|
||||||
self.log.info("wait for node: %s", i)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
)
|
)
|
||||||
|
self.nodes[i].admin_start_sync_file(0)
|
||||||
|
self.log.info("wait for node: %s", i)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
||||||
)
|
)
|
||||||
@ -48,22 +48,26 @@ class CrashTest(TestFramework):
|
|||||||
|
|
||||||
self.start_storage_node(1)
|
self.start_storage_node(1)
|
||||||
self.nodes[1].wait_for_rpc_connection()
|
self.nodes[1].wait_for_rpc_connection()
|
||||||
self.nodes[1].admin_start_sync_file(1)
|
|
||||||
wait_until(lambda: self.nodes[1].zgs_get_file_info(data_root) is not None)
|
wait_until(lambda: self.nodes[1].zgs_get_file_info(data_root) is not None)
|
||||||
|
self.nodes[1].admin_start_sync_file(1)
|
||||||
wait_until(lambda: self.nodes[1].zgs_get_file_info(data_root)["finalized"])
|
wait_until(lambda: self.nodes[1].zgs_get_file_info(data_root)["finalized"])
|
||||||
|
|
||||||
for i in range(2, self.num_nodes):
|
for i in range(2, self.num_nodes):
|
||||||
self.start_storage_node(i)
|
self.start_storage_node(i)
|
||||||
self.nodes[i].wait_for_rpc_connection()
|
self.nodes[i].wait_for_rpc_connection()
|
||||||
|
wait_until(
|
||||||
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
|
)
|
||||||
self.nodes[i].admin_start_sync_file(1)
|
self.nodes[i].admin_start_sync_file(1)
|
||||||
|
|
||||||
self.nodes[i].stop(kill=True)
|
self.nodes[i].stop(kill=True)
|
||||||
self.start_storage_node(i)
|
self.start_storage_node(i)
|
||||||
self.nodes[i].wait_for_rpc_connection()
|
self.nodes[i].wait_for_rpc_connection()
|
||||||
self.nodes[i].admin_start_sync_file(1)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
)
|
)
|
||||||
|
self.nodes[i].admin_start_sync_file(1)
|
||||||
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
||||||
)
|
)
|
||||||
@ -91,10 +95,10 @@ class CrashTest(TestFramework):
|
|||||||
self.log.info("wait for node: %s", i)
|
self.log.info("wait for node: %s", i)
|
||||||
self.start_storage_node(i)
|
self.start_storage_node(i)
|
||||||
self.nodes[i].wait_for_rpc_connection()
|
self.nodes[i].wait_for_rpc_connection()
|
||||||
self.nodes[i].admin_start_sync_file(2)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
)
|
)
|
||||||
|
self.nodes[i].admin_start_sync_file(2)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
||||||
)
|
)
|
||||||
@ -132,18 +136,18 @@ class CrashTest(TestFramework):
|
|||||||
self.log.info("wait for node: %s", i)
|
self.log.info("wait for node: %s", i)
|
||||||
self.start_storage_node(i)
|
self.start_storage_node(i)
|
||||||
self.nodes[i].wait_for_rpc_connection()
|
self.nodes[i].wait_for_rpc_connection()
|
||||||
self.nodes[i].admin_start_sync_file(4)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root1) is not None
|
lambda: self.nodes[i].zgs_get_file_info(data_root1) is not None
|
||||||
)
|
)
|
||||||
|
self.nodes[i].admin_start_sync_file(4)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root1)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root1)["finalized"]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.nodes[i].admin_start_sync_file(3)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
)
|
)
|
||||||
|
self.nodes[i].admin_start_sync_file(3)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
||||||
)
|
)
|
||||||
|
@ -81,6 +81,7 @@ class RpcTest(TestFramework):
|
|||||||
|
|
||||||
for i in range(1, self.num_nodes):
|
for i in range(1, self.num_nodes):
|
||||||
self.log.info("wait node %d", i)
|
self.log.info("wait node %d", i)
|
||||||
|
wait_until(lambda: self.nodes[i].zgs_get_file_info(root) is not None)
|
||||||
self.nodes[i].admin_start_sync_file(n_files - 1)
|
self.nodes[i].admin_start_sync_file(n_files - 1)
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
||||||
@ -88,7 +89,6 @@ class RpcTest(TestFramework):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
wait_until(lambda: self.nodes[i].zgs_get_file_info(root) is not None)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(root)["finalized"]
|
||||||
)
|
)
|
||||||
|
@ -76,16 +76,19 @@ class SubmissionTest(TestFramework):
|
|||||||
if node_idx == i:
|
if node_idx == i:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Wait for log entry before file sync, otherwise, admin_startSyncFile will be failed.
|
||||||
|
wait_until(
|
||||||
|
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
||||||
|
)
|
||||||
|
|
||||||
self.nodes[i].admin_start_sync_file(submission_index - 1)
|
self.nodes[i].admin_start_sync_file(submission_index - 1)
|
||||||
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
lambda: self.nodes[i].sycn_status_is_completed_or_unknown(
|
||||||
submission_index - 1
|
submission_index - 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
wait_until(
|
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root) is not None
|
|
||||||
)
|
|
||||||
wait_until(
|
wait_until(
|
||||||
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
lambda: self.nodes[i].zgs_get_file_info(data_root)["finalized"]
|
||||||
)
|
)
|
||||||
|
@ -5,6 +5,7 @@ import shutil
|
|||||||
import stat
|
import stat
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from concurrent.futures import ProcessPoolExecutor
|
from concurrent.futures import ProcessPoolExecutor
|
||||||
|
|
||||||
@ -18,6 +19,9 @@ __file_path__ = os.path.dirname(os.path.realpath(__file__))
|
|||||||
|
|
||||||
CONFLUX_BINARY = "conflux.exe" if is_windows_platform() else "conflux"
|
CONFLUX_BINARY = "conflux.exe" if is_windows_platform() else "conflux"
|
||||||
|
|
||||||
|
def print_testcase_result(color, glyph, script, start_time):
|
||||||
|
print(color[1] + glyph + " Testcase " + script + "\telapsed: " + str(int(time.time() - start_time)) + " seconds" + color[0], flush=True)
|
||||||
|
|
||||||
def run_single_test(py, script, test_dir, index, port_min, port_max):
|
def run_single_test(py, script, test_dir, index, port_min, port_max):
|
||||||
try:
|
try:
|
||||||
# Make sure python thinks it can write unicode to its stdout
|
# Make sure python thinks it can write unicode to its stdout
|
||||||
@ -31,17 +35,16 @@ def run_single_test(py, script, test_dir, index, port_min, port_max):
|
|||||||
CIRCLE = "o "
|
CIRCLE = "o "
|
||||||
|
|
||||||
BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
|
BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
|
||||||
if os.name == "posix":
|
if os.name == "posix" or os.name == "nt":
|
||||||
# primitive formatting on supported
|
# primitive formatting on supported
|
||||||
# terminal via ANSI escape sequences:
|
# terminal via ANSI escape sequences:
|
||||||
BOLD = ("\033[0m", "\033[1m")
|
BOLD = ("\033[0m", "\033[1m")
|
||||||
BLUE = ("\033[0m", "\033[0;34m")
|
BLUE = ("\033[0m", "\033[0;34m")
|
||||||
RED = ("\033[0m", "\033[0;31m")
|
RED = ("\033[0m", "\033[0;31m")
|
||||||
GREY = ("\033[0m", "\033[1;30m")
|
GREY = ("\033[0m", "\033[1;30m")
|
||||||
print("Running " + script)
|
print("Running " + script, flush=True)
|
||||||
port_min = port_min + (index * PORT_RANGE) % (port_max - port_min)
|
port_min = port_min + (index * PORT_RANGE) % (port_max - port_min)
|
||||||
color = BLUE
|
start_time = time.time()
|
||||||
glyph = TICK
|
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(
|
subprocess.check_output(
|
||||||
args=[py, script, "--randomseed=1", f"--port-min={port_min}"],
|
args=[py, script, "--randomseed=1", f"--port-min={port_min}"],
|
||||||
@ -49,15 +52,13 @@ def run_single_test(py, script, test_dir, index, port_min, port_max):
|
|||||||
cwd=test_dir,
|
cwd=test_dir,
|
||||||
)
|
)
|
||||||
except subprocess.CalledProcessError as err:
|
except subprocess.CalledProcessError as err:
|
||||||
color = RED
|
print_testcase_result(RED, CROSS, script, start_time)
|
||||||
glyph = CROSS
|
print("Output of " + script + "\n" + err.output.decode("utf-8"), flush=True)
|
||||||
print(color[1] + glyph + " Testcase " + script + color[0])
|
|
||||||
print("Output of " + script + "\n" + err.output.decode("utf-8"))
|
|
||||||
raise err
|
raise err
|
||||||
print(color[1] + glyph + " Testcase " + script + color[0])
|
print_testcase_result(BLUE, TICK, script, start_time)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
start_time = time.time()
|
||||||
dir_name = os.path.join(__file_path__, "tmp")
|
dir_name = os.path.join(__file_path__, "tmp")
|
||||||
if not os.path.exists(dir_name):
|
if not os.path.exists(dir_name):
|
||||||
os.makedirs(dir_name, exist_ok=True)
|
os.makedirs(dir_name, exist_ok=True)
|
||||||
@ -95,7 +96,7 @@ def run():
|
|||||||
"", # include test_dir itself
|
"", # include test_dir itself
|
||||||
]
|
]
|
||||||
|
|
||||||
slow_tests = {}
|
slow_tests = {"random_test.py", "same_root_test.py"}
|
||||||
long_manual_tests = {"fuzz_test.py"}
|
long_manual_tests = {"fuzz_test.py"}
|
||||||
|
|
||||||
for subdir in test_subdirs:
|
for subdir in test_subdirs:
|
||||||
@ -136,6 +137,8 @@ def run():
|
|||||||
print("CalledProcessError " + repr(err))
|
print("CalledProcessError " + repr(err))
|
||||||
failed.add(script)
|
failed.add(script)
|
||||||
|
|
||||||
|
print("Elapsed: " + str(int(time.time() - start_time)) + " seconds", flush=True)
|
||||||
|
|
||||||
if len(failed) > 0:
|
if len(failed) > 0:
|
||||||
print("The following test fails: ")
|
print("The following test fails: ")
|
||||||
for c in failed:
|
for c in failed:
|
||||||
|
@ -149,7 +149,7 @@ class TestNode:
|
|||||||
else:
|
else:
|
||||||
self.process.terminate()
|
self.process.terminate()
|
||||||
if wait:
|
if wait:
|
||||||
self.wait_until_stopped()
|
self.wait_until_stopped(close_stdout_stderr=False)
|
||||||
# Check that stderr is as expected
|
# Check that stderr is as expected
|
||||||
self.stderr.seek(0)
|
self.stderr.seek(0)
|
||||||
stderr = self.stderr.read().decode("utf-8").strip()
|
stderr = self.stderr.read().decode("utf-8").strip()
|
||||||
@ -169,12 +169,18 @@ class TestNode:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.__safe_close_stdout_stderr__()
|
||||||
|
|
||||||
|
def __safe_close_stdout_stderr__(self):
|
||||||
|
if self.stdout is not None:
|
||||||
self.stdout.close()
|
self.stdout.close()
|
||||||
self.stderr.close()
|
|
||||||
self.stdout = None
|
self.stdout = None
|
||||||
|
|
||||||
|
if self.stderr is not None:
|
||||||
|
self.stderr.close()
|
||||||
self.stderr = None
|
self.stderr = None
|
||||||
|
|
||||||
def is_node_stopped(self):
|
def __is_node_stopped__(self):
|
||||||
"""Checks whether the node has stopped.
|
"""Checks whether the node has stopped.
|
||||||
|
|
||||||
Returns True if the node has stopped. False otherwise.
|
Returns True if the node has stopped. False otherwise.
|
||||||
@ -196,8 +202,10 @@ class TestNode:
|
|||||||
self.return_code = return_code
|
self.return_code = return_code
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def wait_until_stopped(self, timeout=20):
|
def wait_until_stopped(self, close_stdout_stderr=True, timeout=20):
|
||||||
wait_until(self.is_node_stopped, timeout=timeout)
|
wait_until(self.__is_node_stopped__, timeout=timeout)
|
||||||
|
if close_stdout_stderr:
|
||||||
|
self.__safe_close_stdout_stderr__()
|
||||||
|
|
||||||
|
|
||||||
class BlockchainNode(TestNode):
|
class BlockchainNode(TestNode):
|
||||||
|
@ -326,25 +326,35 @@ class TestFramework:
|
|||||||
"--file",
|
"--file",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
output = tempfile.NamedTemporaryFile(dir=self.root_dir, delete=False, prefix="zgs_client_output_")
|
||||||
|
output_name = output.name
|
||||||
|
output_fileno = output.fileno()
|
||||||
|
|
||||||
|
try:
|
||||||
proc = subprocess.Popen(
|
proc = subprocess.Popen(
|
||||||
upload_args + [file_to_upload.name],
|
upload_args + [file_to_upload.name],
|
||||||
text=True,
|
text=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=output_fileno,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=output_fileno,
|
||||||
)
|
)
|
||||||
proc.wait()
|
|
||||||
|
|
||||||
root = None
|
return_code = proc.wait(timeout=60)
|
||||||
lines = proc.stdout.readlines()
|
|
||||||
|
output.seek(0)
|
||||||
|
lines = output.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
|
line = line.decode("utf-8")
|
||||||
self.log.debug("line: %s", line)
|
self.log.debug("line: %s", line)
|
||||||
if "root" in line:
|
if "root" in line:
|
||||||
index = line.find("root=")
|
index = line.find("root=")
|
||||||
root = line[index + 5 : -1]
|
root = line[index + 5 : -1]
|
||||||
self.log.info("root: %s", root)
|
except Exception as ex:
|
||||||
|
self.log.error("Failed to upload file via CLI tool, output: %s", output_name)
|
||||||
|
raise ex
|
||||||
|
finally:
|
||||||
|
output.close()
|
||||||
|
|
||||||
assert proc.returncode == 0, "%s upload file failed, log: %s" % (self.cli_binary, lines)
|
assert return_code == 0, "%s upload file failed, output: %s, log: %s" % (self.cli_binary, output_name, lines)
|
||||||
self.log.info("file uploaded")
|
|
||||||
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class RpcCaller:
|
|||||||
if isinstance(parsed, Ok):
|
if isinstance(parsed, Ok):
|
||||||
return parsed.result
|
return parsed.result
|
||||||
else:
|
else:
|
||||||
print(parsed)
|
print("Failed to call RPC, method = %s(%s), error = %s" % (self.method, *args, parsed))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(ex)
|
print("Failed to call RPC, method = %s(%s), exception = %s" % (self.method, *args, ex))
|
||||||
return None
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user