2023-07-21 14:54:09 +01:00
|
|
|
# © Crown-owned copyright 2023, Defence Science and Technology Laboratory UK
|
2023-05-25 14:05:53 +01:00
|
|
|
from pathlib import Path
|
2023-11-29 01:28:40 +00:00
|
|
|
from typing import Any, Dict, Tuple, Union
|
2023-05-25 14:05:53 +01:00
|
|
|
|
2023-06-30 09:08:13 +01:00
|
|
|
import pytest
|
2023-11-15 16:04:16 +00:00
|
|
|
import yaml
|
2023-06-30 09:08:13 +01:00
|
|
|
|
|
|
|
|
from primaite import getLogger
|
2023-11-23 01:40:27 +00:00
|
|
|
from primaite.session.session import PrimaiteSession
|
2023-10-25 13:56:02 +01:00
|
|
|
|
|
|
|
|
# from primaite.environment.primaite_env import Primaite
|
|
|
|
|
# from primaite.primaite_session import PrimaiteSession
|
2023-09-08 16:50:49 +01:00
|
|
|
from primaite.simulator.network.container import Network
|
2024-02-05 08:44:10 +00:00
|
|
|
from primaite.simulator.network.hardware.nodes.host.computer import Computer
|
|
|
|
|
from primaite.simulator.network.hardware.nodes.network.router import ACLAction, Router
|
|
|
|
|
from primaite.simulator.network.hardware.nodes.host.server import Server
|
|
|
|
|
from primaite.simulator.network.hardware.nodes.network.switch import Switch
|
2023-09-08 16:50:49 +01:00
|
|
|
from primaite.simulator.network.networks import arcd_uc2_network
|
2023-11-23 19:49:03 +00:00
|
|
|
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
2023-10-20 12:58:58 +01:00
|
|
|
from primaite.simulator.network.transmission.transport_layer import Port
|
2023-10-27 17:50:41 +01:00
|
|
|
from primaite.simulator.system.applications.application import Application
|
2023-10-10 15:14:47 +01:00
|
|
|
from primaite.simulator.system.core.sys_log import SysLog
|
2023-10-20 12:58:58 +01:00
|
|
|
from primaite.simulator.system.services.service import Service
|
2023-11-16 15:11:03 +00:00
|
|
|
from tests.mock_and_patch.get_session_path_mock import temp_user_sessions_path
|
2023-05-25 14:05:53 +01:00
|
|
|
|
|
|
|
|
ACTION_SPACE_NODE_VALUES = 1
|
|
|
|
|
ACTION_SPACE_NODE_ACTION_VALUES = 1
|
|
|
|
|
|
2023-06-30 09:08:13 +01:00
|
|
|
_LOGGER = getLogger(__name__)
|
|
|
|
|
|
2023-11-16 15:11:03 +00:00
|
|
|
from primaite import PRIMAITE_PATHS
|
|
|
|
|
|
2023-09-06 22:01:51 +01:00
|
|
|
# PrimAITE v3 stuff
|
|
|
|
|
from primaite.simulator.file_system.file_system import FileSystem
|
2024-02-05 08:44:10 +00:00
|
|
|
from primaite.simulator.network.hardware.base import Node
|
2023-06-30 09:08:13 +01:00
|
|
|
|
2023-09-06 22:01:51 +01:00
|
|
|
|
2023-10-20 12:58:58 +01:00
|
|
|
class TestService(Service):
|
|
|
|
|
"""Test Service class"""
|
|
|
|
|
|
2024-01-10 11:58:36 +00:00
|
|
|
def describe_state(self) -> Dict:
|
|
|
|
|
return super().describe_state()
|
|
|
|
|
|
2023-11-23 19:49:03 +00:00
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
kwargs["name"] = "TestService"
|
|
|
|
|
kwargs["port"] = Port.HTTP
|
|
|
|
|
kwargs["protocol"] = IPProtocol.TCP
|
|
|
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
2023-10-20 12:58:58 +01:00
|
|
|
def receive(self, payload: Any, session_id: str, **kwargs) -> bool:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2023-10-27 17:50:41 +01:00
|
|
|
class TestApplication(Application):
|
|
|
|
|
"""Test Application class"""
|
|
|
|
|
|
2023-11-23 22:10:53 +00:00
|
|
|
def __init__(self, **kwargs):
|
|
|
|
|
kwargs["name"] = "TestApplication"
|
|
|
|
|
kwargs["port"] = Port.HTTP
|
|
|
|
|
kwargs["protocol"] = IPProtocol.TCP
|
|
|
|
|
super().__init__(**kwargs)
|
|
|
|
|
|
2023-10-27 17:50:41 +01:00
|
|
|
def describe_state(self) -> Dict:
|
2024-01-10 11:58:36 +00:00
|
|
|
return super().describe_state()
|
2023-10-27 17:50:41 +01:00
|
|
|
|
|
|
|
|
|
2023-09-08 16:50:49 +01:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def uc2_network() -> Network:
|
|
|
|
|
return arcd_uc2_network()
|
|
|
|
|
|
|
|
|
|
|
2023-10-20 12:58:58 +01:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def service(file_system) -> TestService:
|
|
|
|
|
return TestService(
|
|
|
|
|
name="TestService", port=Port.ARP, file_system=file_system, sys_log=SysLog(hostname="test_service")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2023-11-23 22:28:08 +00:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def service_class():
|
|
|
|
|
return TestService
|
|
|
|
|
|
|
|
|
|
|
2023-10-27 17:50:41 +01:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def application(file_system) -> TestApplication:
|
|
|
|
|
return TestApplication(
|
|
|
|
|
name="TestApplication", port=Port.ARP, file_system=file_system, sys_log=SysLog(hostname="test_application")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2023-11-23 22:28:08 +00:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def application_class():
|
|
|
|
|
return TestApplication
|
|
|
|
|
|
|
|
|
|
|
2023-09-06 22:01:51 +01:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def file_system() -> FileSystem:
|
|
|
|
|
return Node(hostname="fs_node").file_system
|
|
|
|
|
|
|
|
|
|
|
2023-09-06 22:26:23 +01:00
|
|
|
# PrimAITE v2 stuff
|
2023-11-15 16:04:16 +00:00
|
|
|
class TempPrimaiteSession(PrimaiteSession):
|
2023-06-30 09:08:13 +01:00
|
|
|
"""
|
|
|
|
|
A temporary PrimaiteSession class.
|
|
|
|
|
|
|
|
|
|
Uses context manager for deletion of files upon exit.
|
|
|
|
|
"""
|
|
|
|
|
|
2023-11-15 16:04:16 +00:00
|
|
|
@classmethod
|
|
|
|
|
def from_config(cls, config_path: Union[str, Path]) -> "TempPrimaiteSession":
|
|
|
|
|
"""Create a temporary PrimaiteSession object from a config file."""
|
|
|
|
|
config_path = Path(config_path)
|
|
|
|
|
with open(config_path, "r") as f:
|
|
|
|
|
config = yaml.safe_load(f)
|
2023-06-30 09:08:13 +01:00
|
|
|
|
2023-11-15 16:04:16 +00:00
|
|
|
return super().from_config(cfg=config)
|
2023-06-30 09:08:13 +01:00
|
|
|
|
2023-11-15 16:04:16 +00:00
|
|
|
def __enter__(self):
|
|
|
|
|
return self
|
2023-06-30 09:08:13 +01:00
|
|
|
|
2023-11-15 16:04:16 +00:00
|
|
|
def __exit__(self, type, value, tb):
|
|
|
|
|
pass
|
2023-06-30 09:08:13 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
2023-11-16 15:11:03 +00:00
|
|
|
def temp_primaite_session(request, monkeypatch) -> TempPrimaiteSession:
|
2023-11-15 16:04:16 +00:00
|
|
|
"""Create a temporary PrimaiteSession object."""
|
2023-11-16 15:19:14 +00:00
|
|
|
monkeypatch.setattr(PRIMAITE_PATHS, "user_sessions_path", temp_user_sessions_path())
|
|
|
|
|
config_path = request.param[0]
|
|
|
|
|
return TempPrimaiteSession.from_config(config_path=config_path)
|
2023-11-29 01:28:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def client_server() -> Tuple[Computer, Server]:
|
2024-02-02 16:55:43 +00:00
|
|
|
network = Network()
|
|
|
|
|
|
2023-11-29 01:28:40 +00:00
|
|
|
# Create Computer
|
2024-02-02 16:55:43 +00:00
|
|
|
computer = Computer(
|
|
|
|
|
hostname="computer",
|
|
|
|
|
ip_address="192.168.1.2",
|
2023-11-29 01:28:40 +00:00
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
2024-02-02 16:55:43 +00:00
|
|
|
start_up_duration=0,
|
2023-11-29 01:28:40 +00:00
|
|
|
)
|
2024-02-02 16:55:43 +00:00
|
|
|
computer.power_on()
|
2023-11-29 01:28:40 +00:00
|
|
|
|
|
|
|
|
# Create Server
|
|
|
|
|
server = Server(
|
2024-02-02 16:55:43 +00:00
|
|
|
hostname="server",
|
|
|
|
|
ip_address="192.168.1.3",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
|
|
|
|
start_up_duration=0,
|
2023-11-29 01:28:40 +00:00
|
|
|
)
|
2024-02-02 16:55:43 +00:00
|
|
|
server.power_on()
|
2023-11-29 01:28:40 +00:00
|
|
|
|
|
|
|
|
# Connect Computer and Server
|
2024-02-05 08:44:10 +00:00
|
|
|
network.connect(computer.network_interface[1], server.network_interface[1])
|
2023-11-29 01:28:40 +00:00
|
|
|
|
|
|
|
|
# Should be linked
|
2024-02-02 16:55:43 +00:00
|
|
|
assert next(iter(network.links.values())).is_up
|
2023-11-29 01:28:40 +00:00
|
|
|
|
|
|
|
|
return computer, server
|
2023-11-29 16:31:21 +00:00
|
|
|
|
|
|
|
|
|
2024-02-02 16:55:43 +00:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def client_switch_server() -> Tuple[Computer, Switch, Server]:
|
|
|
|
|
network = Network()
|
|
|
|
|
|
|
|
|
|
# Create Computer
|
|
|
|
|
computer = Computer(
|
|
|
|
|
hostname="computer",
|
|
|
|
|
ip_address="192.168.1.2",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
|
|
|
|
start_up_duration=0,
|
|
|
|
|
)
|
|
|
|
|
computer.power_on()
|
|
|
|
|
|
|
|
|
|
# Create Server
|
|
|
|
|
server = Server(
|
|
|
|
|
hostname="server",
|
|
|
|
|
ip_address="192.168.1.3",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
|
|
|
|
start_up_duration=0,
|
|
|
|
|
)
|
|
|
|
|
server.power_on()
|
|
|
|
|
|
|
|
|
|
switch = Switch(hostname="switch", start_up_duration=0)
|
|
|
|
|
switch.power_on()
|
|
|
|
|
|
2024-02-05 08:44:10 +00:00
|
|
|
network.connect(endpoint_a=computer.network_interface[1], endpoint_b=switch.switch_ports[1])
|
|
|
|
|
network.connect(endpoint_a=server.network_interface[1], endpoint_b=switch.switch_ports[2])
|
2024-02-02 16:55:43 +00:00
|
|
|
|
|
|
|
|
assert all(link.is_up for link in network.links.values())
|
|
|
|
|
|
|
|
|
|
return computer, switch, server
|
|
|
|
|
|
|
|
|
|
|
2023-11-29 16:31:21 +00:00
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def example_network() -> Network:
|
|
|
|
|
"""
|
|
|
|
|
Create the network used for testing.
|
|
|
|
|
|
|
|
|
|
Should only contain the nodes and links.
|
|
|
|
|
This would act as the base network and services and applications are installed in the relevant test file,
|
|
|
|
|
|
2023-11-30 16:32:31 +00:00
|
|
|
-------------- --------------
|
|
|
|
|
| client_1 |----- ----| server_1 |
|
|
|
|
|
-------------- | -------------- -------------- -------------- | --------------
|
2024-01-09 15:18:31 +00:00
|
|
|
------| switch_2 |------| router_1 |------| switch_1 |------
|
2023-11-30 16:32:31 +00:00
|
|
|
-------------- | -------------- -------------- -------------- | --------------
|
|
|
|
|
| client_2 |---- ----| server_2 |
|
|
|
|
|
-------------- --------------
|
2023-11-29 16:31:21 +00:00
|
|
|
"""
|
|
|
|
|
network = Network()
|
|
|
|
|
|
|
|
|
|
# Router 1
|
2024-02-05 08:44:10 +00:00
|
|
|
router_1 = Router(
|
|
|
|
|
hostname="router_1",
|
|
|
|
|
start_up_duration=0
|
|
|
|
|
)
|
|
|
|
|
router_1.power_on()
|
2023-11-29 16:31:21 +00:00
|
|
|
router_1.configure_port(port=1, ip_address="192.168.1.1", subnet_mask="255.255.255.0")
|
|
|
|
|
router_1.configure_port(port=2, ip_address="192.168.10.1", subnet_mask="255.255.255.0")
|
|
|
|
|
|
|
|
|
|
# Switch 1
|
2024-02-05 08:44:10 +00:00
|
|
|
switch_1 = Switch(
|
|
|
|
|
hostname="switch_1",
|
|
|
|
|
num_ports=8,
|
|
|
|
|
start_up_duration=0
|
|
|
|
|
)
|
|
|
|
|
switch_1.power_on()
|
|
|
|
|
|
|
|
|
|
network.connect(endpoint_a=router_1.network_interface[1], endpoint_b=switch_1.switch_ports[8])
|
2023-11-29 16:31:21 +00:00
|
|
|
router_1.enable_port(1)
|
|
|
|
|
|
|
|
|
|
# Switch 2
|
2024-02-05 08:44:10 +00:00
|
|
|
switch_2 = Switch(
|
|
|
|
|
hostname="switch_2",
|
|
|
|
|
num_ports=8,
|
|
|
|
|
start_up_duration=0
|
|
|
|
|
)
|
|
|
|
|
switch_2.power_on()
|
|
|
|
|
network.connect(endpoint_a=router_1.network_interface[2], endpoint_b=switch_2.switch_ports[8])
|
2023-11-29 16:31:21 +00:00
|
|
|
router_1.enable_port(2)
|
|
|
|
|
|
|
|
|
|
# Client 1
|
|
|
|
|
client_1 = Computer(
|
|
|
|
|
hostname="client_1",
|
|
|
|
|
ip_address="192.168.10.21",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.10.1",
|
2024-02-05 08:44:10 +00:00
|
|
|
start_up_duration=0
|
2023-11-29 16:31:21 +00:00
|
|
|
)
|
2024-02-05 08:44:10 +00:00
|
|
|
client_1.power_on()
|
|
|
|
|
network.connect(endpoint_b=client_1.network_interface[1], endpoint_a=switch_2.switch_ports[1])
|
2023-11-29 16:31:21 +00:00
|
|
|
|
|
|
|
|
# Client 2
|
|
|
|
|
client_2 = Computer(
|
|
|
|
|
hostname="client_2",
|
|
|
|
|
ip_address="192.168.10.22",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.10.1",
|
2024-02-05 08:44:10 +00:00
|
|
|
start_up_duration=0
|
2023-11-29 16:31:21 +00:00
|
|
|
)
|
2024-02-05 08:44:10 +00:00
|
|
|
client_2.power_on()
|
|
|
|
|
network.connect(endpoint_b=client_2.network_interface[1], endpoint_a=switch_2.switch_ports[2])
|
2023-11-29 16:31:21 +00:00
|
|
|
|
2024-02-05 08:44:10 +00:00
|
|
|
# Server 1
|
2023-11-29 16:31:21 +00:00
|
|
|
server_1 = Server(
|
|
|
|
|
hostname="server_1",
|
|
|
|
|
ip_address="192.168.1.10",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
2024-02-05 08:44:10 +00:00
|
|
|
start_up_duration=0
|
2023-11-29 16:31:21 +00:00
|
|
|
)
|
2024-02-05 08:44:10 +00:00
|
|
|
server_1.power_on()
|
|
|
|
|
network.connect(endpoint_b=server_1.network_interface[1], endpoint_a=switch_1.switch_ports[1])
|
2023-11-29 16:31:21 +00:00
|
|
|
|
2024-02-05 08:44:10 +00:00
|
|
|
# DServer 2
|
2023-11-29 16:31:21 +00:00
|
|
|
server_2 = Server(
|
|
|
|
|
hostname="server_2",
|
|
|
|
|
ip_address="192.168.1.14",
|
|
|
|
|
subnet_mask="255.255.255.0",
|
|
|
|
|
default_gateway="192.168.1.1",
|
2024-02-05 08:44:10 +00:00
|
|
|
start_up_duration=0
|
2023-11-29 16:31:21 +00:00
|
|
|
)
|
2024-02-05 08:44:10 +00:00
|
|
|
server_2.power_on()
|
|
|
|
|
network.connect(endpoint_b=server_2.network_interface[1], endpoint_a=switch_1.switch_ports[2])
|
2023-11-29 16:31:21 +00:00
|
|
|
|
|
|
|
|
router_1.acl.add_rule(action=ACLAction.PERMIT, src_port=Port.ARP, dst_port=Port.ARP, position=22)
|
|
|
|
|
router_1.acl.add_rule(action=ACLAction.PERMIT, protocol=IPProtocol.ICMP, position=23)
|
|
|
|
|
|
2024-02-05 08:44:10 +00:00
|
|
|
assert all(link.is_up for link in network.links.values())
|
|
|
|
|
|
|
|
|
|
|
2023-11-29 16:31:21 +00:00
|
|
|
return network
|