Skip to content

Commit f6cbad4

Browse files
authored
Add unit tests to the MCP server (#12)
* added tests * all tests passed
1 parent c9738e7 commit f6cbad4

File tree

6 files changed

+442
-0
lines changed

6 files changed

+442
-0
lines changed

src/tests/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.

src/tests/conftest.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
18+
@pytest.fixture
19+
def sample_queue_data():
20+
return [
21+
{"name": "queue1", "messages": 10, "vhost": "/"},
22+
{"name": "queue2", "messages": 5, "vhost": "/"},
23+
]
24+
25+
26+
@pytest.fixture
27+
def sample_exchange_data():
28+
return [
29+
{"name": "exchange1", "type": "direct", "vhost": "/"},
30+
{"name": "exchange2", "type": "fanout", "vhost": "/"},
31+
]
32+
33+
34+
@pytest.fixture
35+
def sample_vhost_data():
36+
return [{"name": "/"}, {"name": "test-vhost"}]

src/tests/test_admin.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from unittest.mock import MagicMock, patch
16+
17+
import pytest
18+
19+
from src.rabbitmq.admin import RabbitMQAdmin
20+
21+
22+
@pytest.fixture
23+
def admin():
24+
return RabbitMQAdmin("localhost", "user", "pass")
25+
26+
27+
@pytest.fixture
28+
def mock_response():
29+
response = MagicMock()
30+
response.status_code = 200
31+
response.json.return_value = {"test": "data"}
32+
return response
33+
34+
35+
class TestRabbitMQAdmin:
36+
def test_init(self, admin):
37+
assert admin.protocol == "https"
38+
assert admin.base_url == "https://localhost/api"
39+
40+
@patch("src.rabbitmq.admin.requests.request")
41+
def test_list_queues(self, mock_request, admin, mock_response):
42+
mock_request.return_value = mock_response
43+
result = admin.list_queues()
44+
assert result == {"test": "data"}
45+
mock_request.assert_called_once()
46+
47+
@patch("src.rabbitmq.admin.requests.request")
48+
def test_get_queue_info(self, mock_request, admin, mock_response):
49+
mock_request.return_value = mock_response
50+
result = admin.get_queue_info("test-queue")
51+
assert result == {"test": "data"}
52+
53+
@patch("src.rabbitmq.admin.requests.request")
54+
def test_delete_queue(self, mock_request, admin, mock_response):
55+
mock_request.return_value = mock_response
56+
admin.delete_queue("test-queue")
57+
mock_request.assert_called_once()
58+
59+
@patch("src.rabbitmq.admin.requests.request")
60+
def test_purge_queue(self, mock_request, admin, mock_response):
61+
mock_request.return_value = mock_response
62+
admin.purge_queue("test-queue")
63+
mock_request.assert_called_once()
64+
65+
@patch("src.rabbitmq.admin.requests.request")
66+
def test_list_exchanges(self, mock_request, admin, mock_response):
67+
mock_request.return_value = mock_response
68+
result = admin.list_exchanges()
69+
assert result == {"test": "data"}
70+
71+
@patch("src.rabbitmq.admin.requests.request")
72+
def test_get_exchange_info(self, mock_request, admin, mock_response):
73+
mock_request.return_value = mock_response
74+
result = admin.get_exchange_info("test-exchange")
75+
assert result == {"test": "data"}
76+
77+
@patch("src.rabbitmq.admin.requests.request")
78+
def test_delete_exchange(self, mock_request, admin, mock_response):
79+
mock_request.return_value = mock_response
80+
admin.delete_exchange("test-exchange")
81+
mock_request.assert_called_once()
82+
83+
@patch("src.rabbitmq.admin.requests.request")
84+
def test_get_overview(self, mock_request, admin, mock_response):
85+
mock_request.return_value = mock_response
86+
result = admin.get_overview()
87+
assert result == {"test": "data"}
88+
89+
@patch("src.rabbitmq.admin.requests.request")
90+
def test_list_vhosts(self, mock_request, admin, mock_response):
91+
mock_request.return_value = mock_response
92+
result = admin.list_vhosts()
93+
assert result == {"test": "data"}
94+
95+
@patch("src.rabbitmq.admin.requests.request")
96+
def test_get_alarm_status(self, mock_request, admin, mock_response):
97+
mock_request.return_value = mock_response
98+
result = admin.get_alarm_status()
99+
assert result == 200
100+
101+
@patch("src.rabbitmq.admin.requests.request")
102+
def test_get_broker_definition(self, mock_request, admin, mock_response):
103+
mock_request.return_value = mock_response
104+
result = admin.get_broker_definition()
105+
assert result == {"test": "data"}

src/tests/test_connection.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
17+
from src.rabbitmq.connection import RabbitMQConnection, validate_rabbitmq_name
18+
19+
20+
class TestRabbitMQConnection:
21+
def test_init_with_tls(self):
22+
conn = RabbitMQConnection("localhost", "user", "pass", use_tls=True)
23+
assert conn.protocol == "amqps"
24+
assert "amqps://user:pass@localhost:5671" == conn.url
25+
26+
def test_init_without_tls(self):
27+
conn = RabbitMQConnection("localhost", "user", "pass", use_tls=False)
28+
assert conn.protocol == "amqp"
29+
assert "amqp://user:pass@localhost:5671" == conn.url
30+
31+
32+
class TestValidateRabbitMQName:
33+
def test_valid_names(self):
34+
validate_rabbitmq_name("valid-queue", "Queue")
35+
validate_rabbitmq_name("valid_queue", "Queue")
36+
validate_rabbitmq_name("valid.queue", "Queue")
37+
validate_rabbitmq_name("valid:queue", "Queue")
38+
validate_rabbitmq_name("queue123", "Queue")
39+
40+
def test_empty_name(self):
41+
with pytest.raises(ValueError, match="cannot be empty"):
42+
validate_rabbitmq_name("", "Queue")
43+
44+
def test_whitespace_only(self):
45+
with pytest.raises(ValueError, match="cannot be empty"):
46+
validate_rabbitmq_name(" ", "Queue")
47+
48+
def test_invalid_characters(self):
49+
with pytest.raises(ValueError, match="can only contain"):
50+
validate_rabbitmq_name("invalid@queue", "Queue")
51+
52+
def test_too_long(self):
53+
with pytest.raises(ValueError, match="must be less than 255"):
54+
validate_rabbitmq_name("a" * 256, "Queue")

src/tests/test_handlers.py

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from unittest.mock import MagicMock
16+
17+
import pytest
18+
19+
from src.rabbitmq.handlers import (
20+
handle_delete_exchange,
21+
handle_delete_queue,
22+
handle_get_cluster_nodes,
23+
handle_get_definition,
24+
handle_get_exchange_info,
25+
handle_get_guidelines,
26+
handle_get_queue_info,
27+
handle_is_broker_in_alarm,
28+
handle_is_node_in_quorum_critical,
29+
handle_list_connections,
30+
handle_list_consumers,
31+
handle_list_exchanges,
32+
handle_list_queues,
33+
handle_list_shovels,
34+
handle_list_users,
35+
handle_list_vhosts,
36+
handle_purge_queue,
37+
handle_shovel,
38+
)
39+
40+
41+
@pytest.fixture
42+
def mock_admin():
43+
admin = MagicMock()
44+
admin.list_queues.return_value = [{"name": "queue1"}, {"name": "queue2"}]
45+
admin.list_exchanges.return_value = [{"name": "exchange1"}]
46+
admin.list_vhosts.return_value = [{"name": "vhost1"}]
47+
admin.get_queue_info.return_value = {"name": "queue1", "messages": 10}
48+
admin.get_exchange_info.return_value = {"name": "exchange1", "type": "direct"}
49+
admin.get_alarm_status.return_value = 200
50+
admin.get_is_node_quorum_critical.return_value = 200
51+
admin.get_broker_definition.return_value = {"queues": []}
52+
admin.list_shovels.return_value = [{"name": "shovel1"}]
53+
admin.get_shovel_info.return_value = {"name": "shovel1"}
54+
admin.list_connections.return_value = [
55+
{
56+
"auth_mechanism": "PLAIN",
57+
"channels": 1,
58+
"client_properties": {},
59+
"connected_at": 1000000,
60+
"state": "running",
61+
}
62+
]
63+
admin.list_consumers.return_value = [{"queue": "queue1"}]
64+
admin.list_users.return_value = [{"name": "user1"}]
65+
admin.get_cluster_nodes.return_value = [
66+
{
67+
"name": "node1",
68+
"mem_alarm": False,
69+
"disk_free_alarm": False,
70+
"disk_free": 1000,
71+
"mem_limit": 2000,
72+
"mem_used": 1000,
73+
"rates_mode": "basic",
74+
"uptime": 10000,
75+
"running": True,
76+
"queue_created": 5,
77+
"queue_deleted": 1,
78+
"connection_created": 10,
79+
}
80+
]
81+
return admin
82+
83+
84+
class TestHandlers:
85+
def test_handle_list_queues(self, mock_admin):
86+
result = handle_list_queues(mock_admin)
87+
assert result == ["queue1", "queue2"]
88+
89+
def test_handle_list_exchanges(self, mock_admin):
90+
result = handle_list_exchanges(mock_admin)
91+
assert result == ["exchange1"]
92+
93+
def test_handle_list_vhosts(self, mock_admin):
94+
result = handle_list_vhosts(mock_admin)
95+
assert result == ["vhost1"]
96+
97+
def test_handle_get_queue_info(self, mock_admin):
98+
result = handle_get_queue_info(mock_admin, "queue1")
99+
assert result == {"name": "queue1", "messages": 10}
100+
101+
def test_handle_get_exchange_info(self, mock_admin):
102+
result = handle_get_exchange_info(mock_admin, "exchange1")
103+
assert result == {"name": "exchange1", "type": "direct"}
104+
105+
def test_handle_delete_queue(self, mock_admin):
106+
handle_delete_queue(mock_admin, "queue1")
107+
mock_admin.delete_queue.assert_called_once_with("queue1", "/")
108+
109+
def test_handle_purge_queue(self, mock_admin):
110+
handle_purge_queue(mock_admin, "queue1")
111+
mock_admin.purge_queue.assert_called_once_with("queue1", "/")
112+
113+
def test_handle_delete_exchange(self, mock_admin):
114+
handle_delete_exchange(mock_admin, "exchange1")
115+
mock_admin.delete_exchange.assert_called_once_with("exchange1", "/")
116+
117+
def test_handle_is_broker_in_alarm_false(self, mock_admin):
118+
result = handle_is_broker_in_alarm(mock_admin)
119+
assert result is False
120+
121+
def test_handle_is_broker_in_alarm_true(self, mock_admin):
122+
mock_admin.get_alarm_status.return_value = 500
123+
result = handle_is_broker_in_alarm(mock_admin)
124+
assert result is True
125+
126+
def test_handle_is_node_in_quorum_critical_false(self, mock_admin):
127+
result = handle_is_node_in_quorum_critical(mock_admin)
128+
assert result is False
129+
130+
def test_handle_is_node_in_quorum_critical_true(self, mock_admin):
131+
mock_admin.get_is_node_quorum_critical.return_value = 500
132+
result = handle_is_node_in_quorum_critical(mock_admin)
133+
assert result is True
134+
135+
def test_handle_get_definition(self, mock_admin):
136+
result = handle_get_definition(mock_admin)
137+
assert result == {"queues": []}
138+
139+
def test_handle_list_shovels(self, mock_admin):
140+
result = handle_list_shovels(mock_admin)
141+
assert result == [{"name": "shovel1"}]
142+
143+
def test_handle_shovel(self, mock_admin):
144+
result = handle_shovel(mock_admin, "shovel1")
145+
assert result == {"name": "shovel1"}
146+
147+
def test_handle_list_connections(self, mock_admin):
148+
result = handle_list_connections(mock_admin)
149+
assert len(result) == 1
150+
assert result[0]["auth_mechanism"] == "PLAIN"
151+
152+
def test_handle_list_consumers(self, mock_admin):
153+
result = handle_list_consumers(mock_admin)
154+
assert result == [{"queue": "queue1"}]
155+
156+
def test_handle_list_users(self, mock_admin):
157+
result = handle_list_users(mock_admin)
158+
assert result == [{"name": "user1"}]
159+
160+
def test_handle_get_cluster_nodes(self, mock_admin):
161+
result = handle_get_cluster_nodes(mock_admin)
162+
assert len(result) == 1
163+
assert result[0]["name"] == "node1"
164+
assert result[0]["mem_used_in_percentage"] == 50.0
165+
166+
def test_handle_get_guidelines_valid(self):
167+
result = handle_get_guidelines("rabbimq_broker_sizing_guide")
168+
assert isinstance(result, str)
169+
assert len(result) > 0
170+
171+
def test_handle_get_guidelines_invalid(self):
172+
with pytest.raises(ValueError, match="doesn't exist"):
173+
handle_get_guidelines("invalid_guide")

0 commit comments

Comments
 (0)