diff --git a/src/cli/graph.py b/src/cli/graph.py index 088dba739..700d121cd 100644 --- a/src/cli/graph.py +++ b/src/cli/graph.py @@ -1,9 +1,10 @@ +from io import BytesIO from pathlib import Path import click -from cli.rpc import rpc_call +import networkx as nx from rich import print -from warnet.utils import DEFAULT_TAG +from warnet.utils import DEFAULT_TAG, create_cycle_graph, validate_graph_schema @click.group(name="graph") @@ -19,21 +20,19 @@ def graph(): @click.option("--random", is_flag=True) def create(number: int, outfile: Path, version: str, bitcoin_conf: Path, random: bool = False): """ - Create a cycle graph with nodes, and additionally include 7 extra random outbounds per node. + Create a cycle graph with nodes, and include 7 extra random outbounds per node. Returns XML file as string with or without --outfile option """ - print( - rpc_call( - "graph_generate", - { - "n": number, - "outfile": str(outfile) if outfile else "", - "version": version, - "bitcoin_conf": str(bitcoin_conf), - "random": random, - }, - ) - ) + graph = create_cycle_graph(number, version, bitcoin_conf, random) + + if outfile: + file_path = Path(outfile) + nx.write_graphml(graph, file_path, named_key_ids=True) + return f"Generated graph written to file: {outfile}" + bio = BytesIO() + nx.write_graphml(graph, bio, named_key_ids=True) + xml_data = bio.getvalue() + print(xml_data.decode("utf-8")) @graph.command() @@ -42,4 +41,6 @@ def validate(graph: Path): """ Validate a against the schema. """ - print(rpc_call("graph_validate", {"graph_path": Path(graph).as_posix()})) + with open(graph) as f: + graph = nx.parse_graphml(f.read(), node_type=int) + return validate_graph_schema(graph) diff --git a/src/warnet/server.py b/src/warnet/server.py index 3f9b30adb..f6e507215 100644 --- a/src/warnet/server.py +++ b/src/warnet/server.py @@ -15,21 +15,14 @@ import time import traceback from datetime import datetime -from io import BytesIO from pathlib import Path -import jsonschema -import networkx as nx import scenarios from backends import ServiceType from flask import Flask, jsonify, request from flask_jsonrpc.app import JSONRPC from flask_jsonrpc.exceptions import ServerError -from warnet.utils import ( - create_cycle_graph, - gen_config_dir, - validate_graph_schema, -) +from warnet.utils import gen_config_dir from warnet.warnet import Warnet WARNET_SERVER_PORT = 9276 @@ -168,9 +161,6 @@ def setup_rpc(self): self.jsonrpc.register(self.network_status) self.jsonrpc.register(self.network_connected) self.jsonrpc.register(self.network_export) - # Graph - self.jsonrpc.register(self.graph_generate) - self.jsonrpc.register(self.graph_validate) # Debug self.jsonrpc.register(self.generate_deployment) self.jsonrpc.register(self.exec_run) @@ -505,39 +495,6 @@ def thread_start(server: Server, network): self.logger.error(msg) raise ServerError(message=msg) from e - def graph_generate( - self, - n: int, - outfile: str, - version: str, - bitcoin_conf: str | None = None, - random: bool = False, - ) -> str: - try: - graph = create_cycle_graph(n, version, bitcoin_conf, random) - - if outfile: - file_path = Path(outfile) - nx.write_graphml(graph, file_path, named_key_ids=True) - return f"Generated graph written to file: {outfile}" - bio = BytesIO() - nx.write_graphml(graph, bio, named_key_ids=True) - xml_data = bio.getvalue() - return xml_data.decode("utf-8") - except Exception as e: - msg = f"Error generating graph: {e}" - self.logger.error(msg) - raise ServerError(message=msg) from e - - def graph_validate(self, graph_path: str) -> str: - with open(graph_path) as f: - graph = nx.parse_graphml(f.read(), node_type=int, force_multigraph=True) - try: - validate_graph_schema(graph) - except (jsonschema.ValidationError, jsonschema.SchemaError) as e: - raise ServerError(message=f"Schema of {graph_path} is invalid: {e}") from e - return f"Schema of {graph_path} is valid" - def network_down(self, network: str = "warnet") -> str: """ Stop all containers in . diff --git a/test/graph_test.py b/test/graph_test.py index 215f978a7..fd723c9c2 100755 --- a/test/graph_test.py +++ b/test/graph_test.py @@ -7,30 +7,23 @@ from warnet.utils import DEFAULT_TAG base = TestBase() -base.network = False -base.start_server() -with tempfile.TemporaryDirectory() as dir: - tf = f"{dir}/{str(uuid.uuid4())}.graphml" - if base.backend == "compose": - print(f"Server writing test graph directly to {tf}") - print(base.warcli(f"graph create 10 --outfile={tf} --version={DEFAULT_TAG}", network=False)) - base.wait_for_predicate(lambda: Path(tf).exists()) - else: - print(f"Client retrieving test graph from RPC and writing to {tf}") - xml = base.warcli(f"graph create 10 --version={DEFAULT_TAG}", network=False) - print(xml) - with open(tf, "w") as file: - file.write(xml) +# Does not require a running Warnet RPC server yet +test_dir = tempfile.TemporaryDirectory() +tf = f"{test_dir.name}/{str(uuid.uuid4())}.graphml" - # Validate the graph schema - assert "invalid" not in base.warcli(f"graph validate {Path(tf)}", False) - print(f"Graph at {tf} validated successfully") +print(f"CLI tool writing test graph directly to {tf}") +print(base.warcli(f"graph create 10 --outfile={tf} --version={DEFAULT_TAG}", network=False)) +base.wait_for_predicate(lambda: Path(tf).exists()) - # Test that the graph actually works - print(base.warcli(f"network start {Path(tf)}")) - base.wait_for_all_tanks_status(target="running") - base.wait_for_all_edges() - base.warcli("rpc 0 getblockcount") +# Validate the graph schema +assert "invalid" not in base.warcli(f"graph validate {Path(tf)}", False) +print(f"Graph at {tf} validated successfully") +# Test that the graph actually works, now we need a server +base.start_server() +print(base.warcli(f"network start {Path(tf)}")) +base.wait_for_all_tanks_status(target="running") +base.wait_for_all_edges() +base.warcli("rpc 0 getblockcount") base.stop_server()