Skip to content

Commit 7cdec90

Browse files
committed
Merge branch 'master' of https://github.com/Limmen/csle
2 parents 06826cf + a433e4f commit 7cdec90

7 files changed

+330
-0
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ features. We currently support each release for a window of 6 months.
131131
<img src="https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg" width="7%" height="7%" style="margin-left:70px;"/>
132132
</p>
133133

134+
## Datasets
135+
136+
A dataset of 6400 intrusion traces can be found [here](https://zenodo.org/records/10234379).
137+
134138
## Maintainer
135139

136140
<table>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import grpc
2+
from unittest.mock import patch, MagicMock
3+
from csle_common.util.grpc_util import GrpcUtil
4+
5+
6+
class TestGrpcUtilSuite:
7+
"""
8+
Test suite for grpc_util
9+
"""
10+
11+
@patch("grpc.channel_ready_future")
12+
def test_grpc_server_on(self, mock_channel_ready_future) -> None:
13+
"""
14+
Test utility function to test if a given gRPC channel is working or not
15+
16+
:param mock_channel_ready_future: mock_channel_ready_future
17+
:return: None
18+
"""
19+
mock_future = MagicMock()
20+
mock_channel_ready_future.return_value = mock_future
21+
result = GrpcUtil.grpc_server_on(mock_channel_ready_future)
22+
mock_future.result.assert_called()
23+
assert result
24+
25+
@patch("grpc.channel_ready_future")
26+
def test_grpc_server_on_timeout(self, mock_channel_ready_future) -> None:
27+
"""
28+
Test utility function to test if a given gRPC channel is not working
29+
30+
:param mock_channel_ready_future: mock_channel_ready_future
31+
:return: None
32+
"""
33+
mock_future = MagicMock()
34+
mock_future.result.side_effect = grpc.FutureTimeoutError()
35+
mock_channel_ready_future.return_value = mock_future
36+
result = GrpcUtil.grpc_server_on(mock_channel_ready_future)
37+
mock_future.result.assert_called()
38+
assert not result
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
from unittest.mock import patch, MagicMock
2+
from csle_common.util.import_util import ImportUtil
3+
4+
5+
class TestImportUtilSuite:
6+
"""
7+
Test suite for import_util
8+
"""
9+
10+
@patch("os.path.exists")
11+
@patch("csle_common.dao.system_identification.emulation_statistics.EmulationStatistics.from_json_file")
12+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.save_emulation_statistic")
13+
def test_import_emulation_statistics_from_disk_json(
14+
self, mock_save_emulation_statistic, mock_from_json_file, mock_path_exists
15+
) -> None:
16+
"""
17+
Test the method that imports emulation statistics from disk to the metastore
18+
19+
:param mock_save_emulation_statistic: mock_save_emulation_statistic
20+
:param mock_from_json_file: mock_from_json_file
21+
:param mock_path_exists: mock_path_exists
22+
23+
:return: None
24+
"""
25+
mock_path_exists.return_value = True
26+
mock_statistics = MagicMock()
27+
mock_from_json_file.return_value = mock_statistics
28+
input_file = "file.json"
29+
emulation_name = "test_emulation"
30+
ImportUtil.import_emulation_statistics_from_disk_json(input_file=input_file, emulation_name=emulation_name)
31+
32+
mock_path_exists.assert_called()
33+
mock_from_json_file.assert_called_once_with(input_file)
34+
assert mock_statistics.emulation_name == emulation_name
35+
mock_save_emulation_statistic.assert_called()
36+
37+
@patch("os.path.exists")
38+
@patch("csle_common.dao.emulation_config.emulation_trace.EmulationTrace.load_traces_from_disk")
39+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.save_emulation_trace")
40+
def test_import_emulation_traces_from_disk_json(
41+
self, mock_save_emulation_trace, mock_load_traces_from_disk, mock_path_exists
42+
) -> None:
43+
"""
44+
Test the method that imports emulation traces from disk to the metastore
45+
46+
:param mock_save_emulation_trace: mock_save_emulation_trac
47+
:param mock_load_traces_from_disk: mock_load_traces_from_disk
48+
:param mock_path_exists: mock_path_exists
49+
50+
:return: None
51+
"""
52+
mock_path_exists.return_value = True
53+
mock_trace_1 = MagicMock()
54+
mock_trace_2 = MagicMock()
55+
mock_load_traces_from_disk.return_value = [mock_trace_1, mock_trace_2]
56+
input_file = "file.json"
57+
emulation_name = "test_emulation"
58+
ImportUtil.import_emulation_traces_from_disk_json(input_file=input_file, emulation_name=emulation_name)
59+
60+
mock_path_exists.assert_called()
61+
mock_load_traces_from_disk.assert_called()
62+
assert mock_trace_1.emulation_name == emulation_name
63+
assert mock_trace_2.emulation_name == emulation_name
64+
assert mock_save_emulation_trace.call_count == 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import csle_common.constants.constants as constants
2+
from csle_common.util.management_util import ManagementUtil
3+
from unittest.mock import patch
4+
5+
class TestManagementUtilSuite:
6+
"""
7+
Test suite for management util
8+
"""
9+
10+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.list_management_users")
11+
@patch("bcrypt.gensalt")
12+
@patch("bcrypt.hashpw")
13+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.save_management_user")
14+
def test_create_default_management_admin_account(
15+
self, mock_save_management_user, mock_hashpw, mock_gensalt, mock_list_management_users
16+
) -> None:
17+
"""
18+
Test the method that creates the default management admin account
19+
20+
:param mock_save_management_user: mock_save_management_user
21+
:param mock_hashpw: mock_hashpw
22+
:param mock_gensalt: mock_gensalt
23+
:param mock_list_management_users: mock_list_management_users
24+
25+
:return: None
26+
"""
27+
mock_list_management_users.return_value = []
28+
mock_salt = b"salt"
29+
mock_gensalt.return_value = mock_salt
30+
mock_hash = b"hashed_password"
31+
mock_hashpw.return_value = mock_hash
32+
33+
constants.CSLE_ADMIN.MANAGEMENT_USER = "admin"
34+
constants.CSLE_ADMIN.MANAGEMENT_PW = "password"
35+
constants.CSLE_ADMIN.MANAGEMENT_FIRST_NAME = "first"
36+
constants.CSLE_ADMIN.MANAGEMENT_LAST_NAME = "last"
37+
constants.CSLE_ADMIN.MANAGEMENT_ORGANIZATION = "organization"
38+
constants.CSLE_ADMIN.MANAGEMENT_EMAIL = "[email protected]"
39+
40+
ManagementUtil.create_default_management_admin_account()
41+
mock_list_management_users.assert_called_once()
42+
mock_gensalt.assert_called_once()
43+
mock_hashpw.assert_called_once_with(constants.CSLE_ADMIN.MANAGEMENT_PW.encode("utf-8"), mock_salt)
44+
mock_save_management_user.assert_called_once()
45+
46+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.list_management_users")
47+
@patch("bcrypt.gensalt")
48+
@patch("bcrypt.hashpw")
49+
@patch("csle_common.metastore.metastore_facade.MetastoreFacade.save_management_user")
50+
def test_create_default_management_guest_account(
51+
self, mock_save_management_user, mock_hashpw, mock_gensalt, mock_list_management_users
52+
) -> None:
53+
"""
54+
Test the method that creates the default management guest account
55+
56+
:param mock_save_management_user: mock_save_management_user
57+
:param mock_hashpw: mock_hashpw
58+
:param mock_gensalt: mock_gensalt
59+
:param mock_list_management_users: mock_list_management_users
60+
61+
:return: None
62+
"""
63+
mock_list_management_users.return_value = []
64+
mock_salt = b"salt"
65+
mock_gensalt.return_value = mock_salt
66+
mock_hash = b"hashed_password"
67+
mock_hashpw.return_value = mock_hash
68+
69+
constants.CSLE_GUEST.MANAGEMENT_USER = "user"
70+
constants.CSLE_GUEST.MANAGEMENT_PW = "password"
71+
constants.CSLE_GUEST.MANAGEMENT_FIRST_NAME = "guest_first"
72+
constants.CSLE_GUEST.MANAGEMENT_LAST_NAME = "guest_last"
73+
constants.CSLE_GUEST.MANAGEMENT_ORGANIZATION = "guest_organization"
74+
constants.CSLE_GUEST.MANAGEMENT_EMAIL = "[email protected]"
75+
76+
ManagementUtil.create_default_management_guest_account()
77+
mock_list_management_users.assert_called_once()
78+
mock_gensalt.assert_called_once()
79+
mock_hashpw.assert_called_once_with(constants.CSLE_GUEST.MANAGEMENT_PW.encode("utf-8"), mock_salt)
80+
mock_save_management_user.assert_called_once()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from unittest.mock import patch
2+
from csle_common.util.multiprocessing_util import NoDaemonProcess
3+
from csle_common.util.multiprocessing_util import NoDaemonContext
4+
from csle_common.util.multiprocessing_util import NestablePool
5+
6+
7+
class TestMultiprocessingUtilSuite:
8+
"""
9+
Test suite for multiprocessing util
10+
"""
11+
12+
def test_daemon(self) -> None:
13+
"""
14+
Test the process with daemon property set to false
15+
16+
:return: None
17+
"""
18+
result = NoDaemonProcess(target=lambda: None).daemon
19+
assert not result
20+
21+
def test_no_daemon_context(self) -> None:
22+
"""
23+
Test the NoDaemonContext method
24+
25+
:return: None
26+
"""
27+
context = NoDaemonContext()
28+
process = context.Process(target=lambda: None)
29+
assert isinstance(process, NoDaemonProcess)
30+
assert not process.daemon
31+
32+
@patch("multiprocessing.get_context")
33+
def test_nestable_pool_initialization(self, mock_get_context) -> None:
34+
"""
35+
Test the method that initializes the pool
36+
37+
:param mock_get_context: mock_get_context
38+
39+
:return: None
40+
"""
41+
mock_get_context.return_value = NoDaemonContext()
42+
pool = NestablePool()
43+
assert pool
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from csle_common.util.plotting_util import PlottingUtil
2+
from scipy import stats
3+
import numpy as np
4+
5+
6+
class TestPlottingUtilSuite:
7+
"""
8+
Test suite for plotting util
9+
"""
10+
11+
def test_running_average(self) -> None:
12+
"""
13+
Test the function used to compute the running average of the last N elements of a vector x
14+
15+
:return: None
16+
"""
17+
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
18+
N = 3
19+
expected = np.array([1, 2, 3, 3, 4, 5, 6, 7, 8, 9])
20+
result = PlottingUtil.running_average(x, N)
21+
assert result.any() == expected.any()
22+
23+
def test_mean_confidence_interval(self) -> None:
24+
"""
25+
Test function that computes confidence intervals
26+
27+
:return: None
28+
"""
29+
data = np.array([1, 2, 3, 4, 5])
30+
mean, h = PlottingUtil.mean_confidence_interval(data=data, confidence=0.95)
31+
expected_mean = np.mean(data)
32+
expected_se = stats.sem(data)
33+
expected_h = expected_se * stats.t.ppf((1 + 0.95) / 2.0, len(data) - 1)
34+
assert expected_mean == mean
35+
assert expected_h == h
36+
37+
def test_min_max_norm(self) -> None:
38+
"""
39+
Test function that computes min-max normalization of a vector
40+
41+
:return: None
42+
"""
43+
vec = np.array([1, 2, 3, 4, 5])
44+
min_val = 1
45+
max_val = 5
46+
expected = np.array([0.0, 0.25, 0.5, 0.75, 1.0])
47+
result = PlottingUtil.min_max_norm(vec, max_val, min_val)
48+
assert result.any() == expected.any()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from csle_common.util.ssh_util import SSHUtil
2+
from unittest.mock import patch, MagicMock
3+
import pytest
4+
5+
6+
class TestSSHUtilSuite:
7+
"""
8+
Test suite for ssh_util
9+
"""
10+
11+
@pytest.fixture(autouse=True)
12+
def mock_sleep(self):
13+
"""
14+
Mock time.sleep to avoid delays
15+
"""
16+
with patch("time.sleep", return_value=None):
17+
yield
18+
19+
@patch("csle_common.util.ssh_util.SSHUtil.execute_ssh_cmd")
20+
def test_execute_ssh_cmds(self, mock_execute_ssh_cmd) -> None:
21+
"""
22+
Test the method that executes a list of commands over an ssh connection to the emulation
23+
24+
:param mock_execute_ssh_cmd: mock_execute_ssh_cmd
25+
26+
:return: None
27+
"""
28+
mock_execute_ssh_cmd.return_value = (b"output", b"error", 1.0)
29+
cmds = ["ls", "pwd", "whoami"]
30+
conn = MagicMock()
31+
results = SSHUtil.execute_ssh_cmds(cmds, conn)
32+
mock_execute_ssh_cmd.assert_called()
33+
assert results == [(b"output", b"error", 1.0)] * len(cmds)
34+
35+
def test_execute_ssh_cmd(self) -> None:
36+
"""
37+
Test the method that executes an action on the emulation over a ssh connection
38+
39+
:return: None
40+
"""
41+
conn = MagicMock()
42+
mock_transport = MagicMock()
43+
mock_session = MagicMock()
44+
mock_session.exit_status_ready.return_value = True
45+
mock_session.recv_ready.return_value = True
46+
mock_session.recv_stderr_ready.return_value = True
47+
mock_session.recv.side_effect = [b"output", b""]
48+
mock_session.recv_stderr.side_effect = [b"error", b""]
49+
conn.get_transport.return_value = mock_transport
50+
mock_transport.open_session.return_value = mock_session
51+
52+
with pytest.raises(ConnectionError, match="Connection failed"):
53+
SSHUtil.execute_ssh_cmd("ls", conn)

0 commit comments

Comments
 (0)