daemon: added grpc wrapped client tests, added new wrapped class ServiceFileConfig to consolidate associated data for its purpose
This commit is contained in:
parent
6086d1229b
commit
44f81391c4
5 changed files with 1335 additions and 36 deletions
|
@ -5,6 +5,7 @@ gRpc client for interfacing with CORE.
|
|||
import logging
|
||||
import threading
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
from queue import Queue
|
||||
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple
|
||||
|
||||
|
@ -54,7 +55,6 @@ from core.api.grpc.services_pb2 import (
|
|||
GetServicesRequest,
|
||||
ServiceActionRequest,
|
||||
ServiceDefaults,
|
||||
ServiceFileConfig,
|
||||
SetNodeServiceFileRequest,
|
||||
SetNodeServiceRequest,
|
||||
SetServiceDefaultsRequest,
|
||||
|
@ -68,6 +68,7 @@ from core.api.grpc.wlan_pb2 import (
|
|||
)
|
||||
from core.api.grpc.wrappers import Hook
|
||||
from core.emulator.data import IpPrefixes
|
||||
from core.errors import CoreError
|
||||
|
||||
|
||||
class MoveNodesStreamer:
|
||||
|
@ -675,13 +676,17 @@ class CoreGrpcClient:
|
|||
:return: True for success, False otherwise
|
||||
:raises grpc.RpcError: when session or node doesn't exist
|
||||
"""
|
||||
if position and geo:
|
||||
raise CoreError("cannot edit position and geo at same time")
|
||||
position_proto = position.to_proto() if position else None
|
||||
geo_proto = geo.to_proto() if geo else None
|
||||
request = core_pb2.EditNodeRequest(
|
||||
session_id=session_id,
|
||||
node_id=node_id,
|
||||
position=position.to_proto(),
|
||||
position=position_proto,
|
||||
icon=icon,
|
||||
source=source,
|
||||
geo=geo.to_proto(),
|
||||
geo=geo_proto,
|
||||
)
|
||||
response = self.stub.EditNode(request)
|
||||
return response.result
|
||||
|
@ -994,7 +999,7 @@ class CoreGrpcClient:
|
|||
|
||||
def get_node_service_configs(
|
||||
self, session_id: int
|
||||
) -> List[wrappers.NodeServiceData]:
|
||||
) -> List[wrappers.NodeServiceConfig]:
|
||||
"""
|
||||
Get service data for a node.
|
||||
|
||||
|
@ -1005,8 +1010,8 @@ class CoreGrpcClient:
|
|||
request = GetNodeServiceConfigsRequest(session_id=session_id)
|
||||
response = self.stub.GetNodeServiceConfigs(request)
|
||||
node_services = []
|
||||
for service_proto in response.configs:
|
||||
node_service = wrappers.NodeServiceData.from_proto(service_proto)
|
||||
for config in response.configs:
|
||||
node_service = wrappers.NodeServiceConfig.from_proto(config)
|
||||
node_services.append(node_service)
|
||||
return node_services
|
||||
|
||||
|
@ -1065,22 +1070,17 @@ class CoreGrpcClient:
|
|||
return response.result
|
||||
|
||||
def set_node_service_file(
|
||||
self, session_id: int, node_id: int, service: str, file_name: str, data: str
|
||||
self, session_id: int, service_file_config: wrappers.ServiceFileConfig
|
||||
) -> bool:
|
||||
"""
|
||||
Set a service file for a node.
|
||||
|
||||
:param session_id: session id
|
||||
:param node_id: node id
|
||||
:param service: service name
|
||||
:param file_name: file name to save
|
||||
:param data: data to save for file
|
||||
:param service_file_config: configuration to set
|
||||
:return: True for success, False otherwise
|
||||
:raises grpc.RpcError: when session or node doesn't exist
|
||||
"""
|
||||
config = ServiceFileConfig(
|
||||
node_id=node_id, service=service, file=file_name, data=data
|
||||
)
|
||||
config = service_file_config.to_proto()
|
||||
request = SetNodeServiceFileRequest(session_id=session_id, config=config)
|
||||
response = self.stub.SetNodeServiceFile(request)
|
||||
return response.result
|
||||
|
@ -1263,7 +1263,7 @@ class CoreGrpcClient:
|
|||
with open(file_path, "w") as xml_file:
|
||||
xml_file.write(response.data)
|
||||
|
||||
def open_xml(self, file_path: str, start: bool = False) -> Tuple[bool, int]:
|
||||
def open_xml(self, file_path: Path, start: bool = False) -> Tuple[bool, int]:
|
||||
"""
|
||||
Load a local scenario XML file to open as a new session.
|
||||
|
||||
|
@ -1271,9 +1271,9 @@ class CoreGrpcClient:
|
|||
:param start: tuple of result and session id when successful
|
||||
:return: tuple of result and session id
|
||||
"""
|
||||
with open(file_path, "r") as xml_file:
|
||||
data = xml_file.read()
|
||||
request = core_pb2.OpenXmlRequest(data=data, start=start, file=file_path)
|
||||
with file_path.open("r") as f:
|
||||
data = f.read()
|
||||
request = core_pb2.OpenXmlRequest(data=data, start=start, file=str(file_path))
|
||||
response = self.stub.OpenXml(request)
|
||||
return response.result, response.session_id
|
||||
|
||||
|
|
|
@ -233,6 +233,23 @@ class NodeServiceData:
|
|||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class NodeServiceConfig:
|
||||
node_id: int
|
||||
service: str
|
||||
data: NodeServiceData
|
||||
files: Dict[str, str] = field(default_factory=dict)
|
||||
|
||||
@classmethod
|
||||
def from_proto(cls, proto: services_pb2.NodeServiceConfig) -> "NodeServiceConfig":
|
||||
return NodeServiceConfig(
|
||||
node_id=proto.node_id,
|
||||
service=proto.service,
|
||||
data=NodeServiceData.from_proto(proto.data),
|
||||
files=dict(proto.files),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServiceConfig:
|
||||
node_id: int
|
||||
|
@ -255,6 +272,19 @@ class ServiceConfig:
|
|||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ServiceFileConfig:
|
||||
node_id: int
|
||||
service: str
|
||||
file: str
|
||||
data: str = field(repr=False)
|
||||
|
||||
def to_proto(self) -> services_pb2.ServiceFileConfig:
|
||||
return services_pb2.ServiceFileConfig(
|
||||
node_id=self.node_id, service=self.service, file=self.file, data=self.data
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class BridgeThroughput:
|
||||
node_id: int
|
||||
|
@ -724,6 +754,9 @@ class Session:
|
|||
metadata: Dict[str, str]
|
||||
file: Path
|
||||
|
||||
def set_node(self, node: Node) -> None:
|
||||
self.nodes[node.id] = node
|
||||
|
||||
@classmethod
|
||||
def from_proto(cls, proto: core_pb2.Session) -> "Session":
|
||||
nodes: Dict[int, Node] = {x.id: Node.from_proto(x) for x in proto.nodes}
|
||||
|
|
|
@ -6,6 +6,7 @@ import json
|
|||
import logging
|
||||
import os
|
||||
import tkinter as tk
|
||||
from pathlib import Path
|
||||
from tkinter import messagebox
|
||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple
|
||||
|
||||
|
@ -28,6 +29,7 @@ from core.api.grpc.wrappers import (
|
|||
NodeType,
|
||||
Position,
|
||||
ServiceConfig,
|
||||
ServiceFileConfig,
|
||||
Session,
|
||||
SessionLocation,
|
||||
SessionState,
|
||||
|
@ -551,7 +553,7 @@ class CoreClient:
|
|||
except grpc.RpcError as e:
|
||||
self.app.show_grpc_exception("Save XML Error", e)
|
||||
|
||||
def open_xml(self, file_path: str) -> None:
|
||||
def open_xml(self, file_path: Path) -> None:
|
||||
"""
|
||||
Open core xml
|
||||
"""
|
||||
|
@ -599,17 +601,9 @@ class CoreClient:
|
|||
def set_node_service_file(
|
||||
self, node_id: int, service_name: str, file_name: str, data: str
|
||||
) -> None:
|
||||
result = self.client.set_node_service_file(
|
||||
self.session.id, node_id, service_name, file_name, data
|
||||
)
|
||||
logging.info(
|
||||
"set node(%s) service file, service: %s, file: %s, data: %s, result: %s",
|
||||
node_id,
|
||||
service_name,
|
||||
file_name,
|
||||
data,
|
||||
result,
|
||||
)
|
||||
config = ServiceFileConfig(node_id, service_name, file_name, data)
|
||||
result = self.client.set_node_service_file(self.session.id, config)
|
||||
logging.info("set service file config %s: %s", config, result)
|
||||
|
||||
def create_nodes_and_links(self) -> None:
|
||||
"""
|
||||
|
@ -639,10 +633,8 @@ class CoreClient:
|
|||
self.client.set_mobility_config(self.session.id, node_id, config)
|
||||
for config in self.get_service_configs():
|
||||
self.client.set_node_service(self.session.id, config)
|
||||
for node_id, service, file, data in self.get_service_file_configs():
|
||||
self.client.set_node_service_file(
|
||||
self.session.id, node_id, service, file, data
|
||||
)
|
||||
for config in self.get_service_file_configs():
|
||||
self.client.set_node_service_file(self.session.id, config)
|
||||
for hook in self.session.hooks.values():
|
||||
self.client.add_hook(self.session.id, hook)
|
||||
for config in self.get_emane_model_configs():
|
||||
|
@ -806,7 +798,7 @@ class CoreClient:
|
|||
configs.append(config)
|
||||
return configs
|
||||
|
||||
def get_service_file_configs(self) -> List[Tuple[int, str, str, str]]:
|
||||
def get_service_file_configs(self) -> List[ServiceFileConfig]:
|
||||
configs = []
|
||||
for node in self.session.nodes.values():
|
||||
if not nutils.is_container(node):
|
||||
|
@ -815,7 +807,8 @@ class CoreClient:
|
|||
continue
|
||||
for service, file_configs in node.service_file_configs.items():
|
||||
for file, data in file_configs.items():
|
||||
configs.append((node.id, service, file, data))
|
||||
config = ServiceFileConfig(node.id, service, file, data)
|
||||
configs.append(config)
|
||||
return configs
|
||||
|
||||
def get_config_service_configs_proto(
|
||||
|
|
|
@ -312,6 +312,7 @@ class Menubar(tk.Menu):
|
|||
filetypes=(("XML Files", "*.xml"), ("All Files", "*")),
|
||||
)
|
||||
if file_path:
|
||||
file_path = Path(file_path)
|
||||
self.open_xml_task(file_path)
|
||||
|
||||
def open_xml_task(self, file_path: Path) -> None:
|
||||
|
|
1272
daemon/tests/test_grpcw.py
Normal file
1272
daemon/tests/test_grpcw.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue