77
88from server import NETBOX_OBJECT_TYPES , netbox_search_objects
99
10-
1110# ============================================================================
1211# Parameter Validation Tests
1312# ============================================================================
@@ -44,7 +43,12 @@ def test_invalid_object_type_raises_error():
4443@patch ("server.netbox" )
4544def test_searches_default_types_when_none_specified (mock_netbox ):
4645 """When object_types=None, should search 8 default common types."""
47- mock_netbox .get .return_value = []
46+ mock_netbox .get .return_value = {
47+ "count" : 0 ,
48+ "next" : None ,
49+ "previous" : None ,
50+ "results" : [],
51+ }
4852
4953 result = netbox_search_objects .fn (query = "test" )
5054
@@ -57,7 +61,12 @@ def test_searches_default_types_when_none_specified(mock_netbox):
5761@patch ("server.netbox" )
5862def test_custom_object_types_limits_search_scope (mock_netbox ):
5963 """When object_types specified, should only search those types."""
60- mock_netbox .get .return_value = []
64+ mock_netbox .get .return_value = {
65+ "count" : 0 ,
66+ "next" : None ,
67+ "previous" : None ,
68+ "results" : [],
69+ }
6170
6271 result = netbox_search_objects .fn (query = "test" , object_types = ["devices" , "sites" ])
6372
@@ -74,7 +83,12 @@ def test_custom_object_types_limits_search_scope(mock_netbox):
7483@patch ("server.netbox" )
7584def test_field_projection_applied_to_queries (mock_netbox ):
7685 """When fields specified, should apply to all queries as comma-separated string."""
77- mock_netbox .get .return_value = []
86+ mock_netbox .get .return_value = {
87+ "count" : 0 ,
88+ "next" : None ,
89+ "previous" : None ,
90+ "results" : [],
91+ }
7892
7993 netbox_search_objects .fn (
8094 query = "test" , object_types = ["devices" , "sites" ], fields = ["id" , "name" ]
@@ -97,8 +111,13 @@ def test_result_structure_with_empty_and_populated_results(mock_netbox):
97111
98112 def mock_get_side_effect (endpoint , params ):
99113 if "devices" in endpoint :
100- return [{"id" : 1 , "name" : "device01" }]
101- return []
114+ return {
115+ "count" : 1 ,
116+ "next" : None ,
117+ "previous" : None ,
118+ "results" : [{"id" : 1 , "name" : "device01" }],
119+ }
120+ return {"count" : 0 , "next" : None , "previous" : None , "results" : []}
102121
103122 mock_netbox .get .side_effect = mock_get_side_effect
104123
@@ -128,8 +147,13 @@ def mock_get_side_effect(endpoint, params):
128147 if "devices" in endpoint :
129148 raise Exception ("API error" )
130149 elif "sites" in endpoint :
131- return [{"id" : 1 , "name" : "site01" }]
132- return []
150+ return {
151+ "count" : 1 ,
152+ "next" : None ,
153+ "previous" : None ,
154+ "results" : [{"id" : 1 , "name" : "site01" }],
155+ }
156+ return {"count" : 0 , "next" : None , "previous" : None , "results" : []}
133157
134158 mock_netbox .get .side_effect = mock_get_side_effect
135159
@@ -149,7 +173,12 @@ def mock_get_side_effect(endpoint, params):
149173@patch ("server.netbox" )
150174def test_api_parameters_passed_correctly (mock_netbox ):
151175 """Should pass query, limit, and fields to NetBox API correctly."""
152- mock_netbox .get .return_value = []
176+ mock_netbox .get .return_value = {
177+ "count" : 0 ,
178+ "next" : None ,
179+ "previous" : None ,
180+ "results" : [],
181+ }
153182
154183 netbox_search_objects .fn (
155184 query = "switch01" , object_types = ["devices" ], fields = ["id" ], limit = 25
@@ -166,10 +195,58 @@ def test_api_parameters_passed_correctly(mock_netbox):
166195@patch ("server.netbox" )
167196def test_uses_correct_api_endpoints (mock_netbox ):
168197 """Should use correct API endpoints from NETBOX_OBJECT_TYPES mapping."""
169- mock_netbox .get .return_value = []
198+ mock_netbox .get .return_value = {
199+ "count" : 0 ,
200+ "next" : None ,
201+ "previous" : None ,
202+ "results" : [],
203+ }
170204
171205 netbox_search_objects .fn (query = "test" , object_types = ["devices" , "ip-addresses" ])
172206
173207 called_endpoints = [call [0 ][0 ] for call in mock_netbox .get .call_args_list ]
174208 assert NETBOX_OBJECT_TYPES ["devices" ] in called_endpoints
175209 assert NETBOX_OBJECT_TYPES ["ip-addresses" ] in called_endpoints
210+
211+
212+ # ============================================================================
213+ # Paginated Response Handling Tests
214+ # ============================================================================
215+
216+
217+ @patch ("server.netbox" )
218+ def test_extracts_results_from_paginated_response (mock_netbox ):
219+ """Should extract 'results' array from NetBox paginated response structure.
220+
221+ NetBox API returns paginated responses with structure:
222+ {
223+ "count": <total>,
224+ "next": <url or null>,
225+ "previous": <url or null>,
226+ "results": [<objects>]
227+ }
228+
229+ The tool should return just the results arrays, not the full response.
230+ """
231+ # Mock realistic paginated response from NetBox API
232+ mock_netbox .get .return_value = {
233+ "count" : 2 ,
234+ "next" : None ,
235+ "previous" : None ,
236+ "results" : [
237+ {"id" : 1 , "name" : "device01" },
238+ {"id" : 2 , "name" : "device02" },
239+ ],
240+ }
241+
242+ result = netbox_search_objects .fn (query = "test" , object_types = ["devices" ])
243+
244+ # Should return dict with object type as key
245+ assert "devices" in result
246+ # Value should be a list (array), not a dict
247+ assert isinstance (result ["devices" ], list )
248+ # Should contain just the results, not the paginated response wrapper
249+ assert result ["devices" ] == [
250+ {"id" : 1 , "name" : "device01" },
251+ {"id" : 2 , "name" : "device02" },
252+ ]
0 commit comments