Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RemoteBin abstract class #20

Merged
merged 4 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions massa_test_framework/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,29 +233,26 @@ def build_kind(self) -> BuildKind:
else:
return BuildKind.Debug

def bin_path(self, bin_name: str):
"""Relative path (relative to compilation folder) to (rust compiled) binary"""
if self._target:
return Path(f"target/{self._target}/{self.build_kind}/{bin_name}")
else:
return Path(f"target/{self.build_kind}/{bin_name}")

@property
def massa_node(self) -> Path:
"""Relative path (relative to compilation folder) to massa node binary"""
if self._target:
return Path(f"target/{self._target}/{self.build_kind}/massa-node")
else:
return Path(f"target/{self.build_kind}/massa-node")
return self.bin_path("massa-node")

@property
def massa_client(self) -> Path:
"""Relative path (relative to compilation folder) to massa client binary"""
if self._target:
return Path(f"target/{self._target}/{self.build_kind}/massa-client")
else:
return Path(f"target/{self.build_kind}/massa-client")
return self.bin_path("massa-client")

@property
def massa_ledger_editor(self) -> Path:
# TODO: can we factorize this with massa_node & massa_client?
if self._target:
return Path(f"target/{self._target}/{self.build_kind}/massa-ledger-editor")
else:
return Path(f"target/{self.build_kind}/massa-ledger-editor")
return self.bin_path("massa-ledger-editor")

@property
def config_files(self) -> Dict[str, Path]:
Expand Down
115 changes: 115 additions & 0 deletions massa_test_framework/remote_bin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import sys
from contextlib import contextmanager
from pathlib import Path
from dataclasses import dataclass

from typing import Optional, Dict, List

from .server import Server
from .compile import CompileUnit, CompileOpts
from .remote import RemotePath, copy_file


@dataclass
class SrcDst:
sydhds marked this conversation as resolved.
Show resolved Hide resolved
"""Source and Destination paths (usually for copy)"""
src: Path
dst: Path


class RemoteBin:
bilboquet marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, server: Server, compile_unit: CompileUnit):

# Dummy code so the IDE is happy
self.server = server
self.compile_unit = compile_unit
self.start_cmd = [""]

# self.install_folder = self._install(...)
raise NotImplementedError
bilboquet marked this conversation as resolved.
Show resolved Hide resolved

def _install(self, to_install: Dict[str, Path | SrcDst], tmp_prefix: str = "remote_bin") -> Path | RemotePath:
bilboquet marked this conversation as resolved.
Show resolved Hide resolved

"""
Args:
to_install: a dict of key (filename), path (relative path in install folder)
"""

tmp_folder = self.server.mkdtemp(prefix="remote_bin_")
repo = self.compile_unit.repo

for filename, to_install_item in to_install.items():
bilboquet marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(to_install_item, SrcDst):
src = repo / to_install_item.src
dst = tmp_folder / to_install_item.dst
else:
src = repo / to_install_item
dst = tmp_folder / to_install
bilboquet marked this conversation as resolved.
Show resolved Hide resolved

print("server mkdir:", dst.parent)
self.server.mkdir(dst.parent)
print(f"copy_file {src} -> {dst}")
copy_file(src, dst)

return tmp_folder

@classmethod
def from_compile_unit(cls, server: Server, compile_unit: CompileUnit) -> "RemoteBin":
node = cls(server, compile_unit)
return node

@classmethod
def from_dev(
cls, server: Server, repo: Path, build_opts: Optional[List[str]] = None
) -> "RemoteBin":
compile_opts = CompileOpts()
compile_opts.already_compiled = repo
if build_opts:
compile_opts.build_opts = build_opts
cu = CompileUnit(server, compile_opts)
node = cls(server, cu)
return node

@contextmanager
def start(
self,
env: Optional[Dict[str, str]] = None,
args: Optional[List[str]] = None,
stdout=sys.stdout,
stderr=sys.stderr,
):
cmd = " ".join(self.start_cmd)
if args:
args_joined = " ".join(args)
if args_joined:
cmd += " "
cmd += args_joined

print(f"{cmd=}")
process = self.server.run(
[cmd],
cwd=str(self.install_folder),
env=env,
stdout=stdout,
stderr=stderr,
)
with process as p:
try:
yield p
except Exception:
# Note: Need to catch every exception here as we need to stop subprocess.Popen
# otherwise it will wait forever
# so first print traceback then stop the process
import traceback

print(traceback.format_exc())
self.stop(p)
# Re Raise exception so test will be marked as failed
raise
else:
# Note: normal end
self.stop(p)

def stop(self, process):
pass