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 logging
|
||||||
import threading
|
import threading
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple
|
from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tuple
|
||||||
|
|
||||||
|
@ -54,7 +55,6 @@ from core.api.grpc.services_pb2 import (
|
||||||
GetServicesRequest,
|
GetServicesRequest,
|
||||||
ServiceActionRequest,
|
ServiceActionRequest,
|
||||||
ServiceDefaults,
|
ServiceDefaults,
|
||||||
ServiceFileConfig,
|
|
||||||
SetNodeServiceFileRequest,
|
SetNodeServiceFileRequest,
|
||||||
SetNodeServiceRequest,
|
SetNodeServiceRequest,
|
||||||
SetServiceDefaultsRequest,
|
SetServiceDefaultsRequest,
|
||||||
|
@ -68,6 +68,7 @@ from core.api.grpc.wlan_pb2 import (
|
||||||
)
|
)
|
||||||
from core.api.grpc.wrappers import Hook
|
from core.api.grpc.wrappers import Hook
|
||||||
from core.emulator.data import IpPrefixes
|
from core.emulator.data import IpPrefixes
|
||||||
|
from core.errors import CoreError
|
||||||
|
|
||||||
|
|
||||||
class MoveNodesStreamer:
|
class MoveNodesStreamer:
|
||||||
|
@ -675,13 +676,17 @@ class CoreGrpcClient:
|
||||||
:return: True for success, False otherwise
|
:return: True for success, False otherwise
|
||||||
:raises grpc.RpcError: when session or node doesn't exist
|
: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(
|
request = core_pb2.EditNodeRequest(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
node_id=node_id,
|
node_id=node_id,
|
||||||
position=position.to_proto(),
|
position=position_proto,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
source=source,
|
source=source,
|
||||||
geo=geo.to_proto(),
|
geo=geo_proto,
|
||||||
)
|
)
|
||||||
response = self.stub.EditNode(request)
|
response = self.stub.EditNode(request)
|
||||||
return response.result
|
return response.result
|
||||||
|
@ -994,7 +999,7 @@ class CoreGrpcClient:
|
||||||
|
|
||||||
def get_node_service_configs(
|
def get_node_service_configs(
|
||||||
self, session_id: int
|
self, session_id: int
|
||||||
) -> List[wrappers.NodeServiceData]:
|
) -> List[wrappers.NodeServiceConfig]:
|
||||||
"""
|
"""
|
||||||
Get service data for a node.
|
Get service data for a node.
|
||||||
|
|
||||||
|
@ -1005,8 +1010,8 @@ class CoreGrpcClient:
|
||||||
request = GetNodeServiceConfigsRequest(session_id=session_id)
|
request = GetNodeServiceConfigsRequest(session_id=session_id)
|
||||||
response = self.stub.GetNodeServiceConfigs(request)
|
response = self.stub.GetNodeServiceConfigs(request)
|
||||||
node_services = []
|
node_services = []
|
||||||
for service_proto in response.configs:
|
for config in response.configs:
|
||||||
node_service = wrappers.NodeServiceData.from_proto(service_proto)
|
node_service = wrappers.NodeServiceConfig.from_proto(config)
|
||||||
node_services.append(node_service)
|
node_services.append(node_service)
|
||||||
return node_services
|
return node_services
|
||||||
|
|
||||||
|
@ -1065,22 +1070,17 @@ class CoreGrpcClient:
|
||||||
return response.result
|
return response.result
|
||||||
|
|
||||||
def set_node_service_file(
|
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:
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Set a service file for a node.
|
Set a service file for a node.
|
||||||
|
|
||||||
:param session_id: session id
|
:param session_id: session id
|
||||||
:param node_id: node id
|
:param service_file_config: configuration to set
|
||||||
:param service: service name
|
|
||||||
:param file_name: file name to save
|
|
||||||
:param data: data to save for file
|
|
||||||
:return: True for success, False otherwise
|
:return: True for success, False otherwise
|
||||||
:raises grpc.RpcError: when session or node doesn't exist
|
:raises grpc.RpcError: when session or node doesn't exist
|
||||||
"""
|
"""
|
||||||
config = ServiceFileConfig(
|
config = service_file_config.to_proto()
|
||||||
node_id=node_id, service=service, file=file_name, data=data
|
|
||||||
)
|
|
||||||
request = SetNodeServiceFileRequest(session_id=session_id, config=config)
|
request = SetNodeServiceFileRequest(session_id=session_id, config=config)
|
||||||
response = self.stub.SetNodeServiceFile(request)
|
response = self.stub.SetNodeServiceFile(request)
|
||||||
return response.result
|
return response.result
|
||||||
|
@ -1263,7 +1263,7 @@ class CoreGrpcClient:
|
||||||
with open(file_path, "w") as xml_file:
|
with open(file_path, "w") as xml_file:
|
||||||
xml_file.write(response.data)
|
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.
|
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
|
:param start: tuple of result and session id when successful
|
||||||
:return: tuple of result and session id
|
:return: tuple of result and session id
|
||||||
"""
|
"""
|
||||||
with open(file_path, "r") as xml_file:
|
with file_path.open("r") as f:
|
||||||
data = xml_file.read()
|
data = f.read()
|
||||||
request = core_pb2.OpenXmlRequest(data=data, start=start, file=file_path)
|
request = core_pb2.OpenXmlRequest(data=data, start=start, file=str(file_path))
|
||||||
response = self.stub.OpenXml(request)
|
response = self.stub.OpenXml(request)
|
||||||
return response.result, response.session_id
|
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
|
@dataclass
|
||||||
class ServiceConfig:
|
class ServiceConfig:
|
||||||
node_id: int
|
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
|
@dataclass
|
||||||
class BridgeThroughput:
|
class BridgeThroughput:
|
||||||
node_id: int
|
node_id: int
|
||||||
|
@ -724,6 +754,9 @@ class Session:
|
||||||
metadata: Dict[str, str]
|
metadata: Dict[str, str]
|
||||||
file: Path
|
file: Path
|
||||||
|
|
||||||
|
def set_node(self, node: Node) -> None:
|
||||||
|
self.nodes[node.id] = node
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_proto(cls, proto: core_pb2.Session) -> "Session":
|
def from_proto(cls, proto: core_pb2.Session) -> "Session":
|
||||||
nodes: Dict[int, Node] = {x.id: Node.from_proto(x) for x in proto.nodes}
|
nodes: Dict[int, Node] = {x.id: Node.from_proto(x) for x in proto.nodes}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
from pathlib import Path
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple
|
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Set, Tuple
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ from core.api.grpc.wrappers import (
|
||||||
NodeType,
|
NodeType,
|
||||||
Position,
|
Position,
|
||||||
ServiceConfig,
|
ServiceConfig,
|
||||||
|
ServiceFileConfig,
|
||||||
Session,
|
Session,
|
||||||
SessionLocation,
|
SessionLocation,
|
||||||
SessionState,
|
SessionState,
|
||||||
|
@ -551,7 +553,7 @@ class CoreClient:
|
||||||
except grpc.RpcError as e:
|
except grpc.RpcError as e:
|
||||||
self.app.show_grpc_exception("Save XML Error", 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
|
Open core xml
|
||||||
"""
|
"""
|
||||||
|
@ -599,17 +601,9 @@ class CoreClient:
|
||||||
def set_node_service_file(
|
def set_node_service_file(
|
||||||
self, node_id: int, service_name: str, file_name: str, data: str
|
self, node_id: int, service_name: str, file_name: str, data: str
|
||||||
) -> None:
|
) -> None:
|
||||||
result = self.client.set_node_service_file(
|
config = ServiceFileConfig(node_id, service_name, file_name, data)
|
||||||
self.session.id, 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)
|
||||||
logging.info(
|
|
||||||
"set node(%s) service file, service: %s, file: %s, data: %s, result: %s",
|
|
||||||
node_id,
|
|
||||||
service_name,
|
|
||||||
file_name,
|
|
||||||
data,
|
|
||||||
result,
|
|
||||||
)
|
|
||||||
|
|
||||||
def create_nodes_and_links(self) -> None:
|
def create_nodes_and_links(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -639,10 +633,8 @@ class CoreClient:
|
||||||
self.client.set_mobility_config(self.session.id, node_id, config)
|
self.client.set_mobility_config(self.session.id, node_id, config)
|
||||||
for config in self.get_service_configs():
|
for config in self.get_service_configs():
|
||||||
self.client.set_node_service(self.session.id, config)
|
self.client.set_node_service(self.session.id, config)
|
||||||
for node_id, service, file, data in self.get_service_file_configs():
|
for config in self.get_service_file_configs():
|
||||||
self.client.set_node_service_file(
|
self.client.set_node_service_file(self.session.id, config)
|
||||||
self.session.id, node_id, service, file, data
|
|
||||||
)
|
|
||||||
for hook in self.session.hooks.values():
|
for hook in self.session.hooks.values():
|
||||||
self.client.add_hook(self.session.id, hook)
|
self.client.add_hook(self.session.id, hook)
|
||||||
for config in self.get_emane_model_configs():
|
for config in self.get_emane_model_configs():
|
||||||
|
@ -806,7 +798,7 @@ class CoreClient:
|
||||||
configs.append(config)
|
configs.append(config)
|
||||||
return configs
|
return configs
|
||||||
|
|
||||||
def get_service_file_configs(self) -> List[Tuple[int, str, str, str]]:
|
def get_service_file_configs(self) -> List[ServiceFileConfig]:
|
||||||
configs = []
|
configs = []
|
||||||
for node in self.session.nodes.values():
|
for node in self.session.nodes.values():
|
||||||
if not nutils.is_container(node):
|
if not nutils.is_container(node):
|
||||||
|
@ -815,7 +807,8 @@ class CoreClient:
|
||||||
continue
|
continue
|
||||||
for service, file_configs in node.service_file_configs.items():
|
for service, file_configs in node.service_file_configs.items():
|
||||||
for file, data in 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
|
return configs
|
||||||
|
|
||||||
def get_config_service_configs_proto(
|
def get_config_service_configs_proto(
|
||||||
|
|
|
@ -312,6 +312,7 @@ class Menubar(tk.Menu):
|
||||||
filetypes=(("XML Files", "*.xml"), ("All Files", "*")),
|
filetypes=(("XML Files", "*.xml"), ("All Files", "*")),
|
||||||
)
|
)
|
||||||
if file_path:
|
if file_path:
|
||||||
|
file_path = Path(file_path)
|
||||||
self.open_xml_task(file_path)
|
self.open_xml_task(file_path)
|
||||||
|
|
||||||
def open_xml_task(self, file_path: Path) -> None:
|
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…
Add table
Reference in a new issue