1- from unittest .mock import patch
2-
31import pytest
4- import requests
52from src .models .authentication import Authentication
63from src .models .incident import XSOARSearchIncidentsResponse
74from src .services .client_api import PaloAltoCortexXSOARClientAPI
@@ -17,187 +14,49 @@ def api_client(auth):
1714 return PaloAltoCortexXSOARClientAPI (auth = auth , api_url = "https://test.xsoar.com" )
1815
1916
20- def test_search_incidents_success (api_client ):
21- mock_response = {
22- "total" : 1 ,
23- "data" : [
24- {
25- "id" : "1" ,
26- "name" : "Test Incident" ,
27- "CustomFields" : {
28- "xdralerts" : [
29- {"alert_id" : "alert1" , "detection_timestamp" : 1600000000000 }
30- ]
31- },
32- }
33- ],
34- }
35-
36- with patch ("requests.Session.post" ) as mock_post :
37- mock_post .return_value .json .return_value = mock_response
38- mock_post .return_value .status_code = 200
39-
40- response = api_client .search_incidents (
41- from_date = "2023-01-01T00:00:00Z" ,
42- to_date = "2023-01-01T23:59:59Z" ,
43- search_from = 0 ,
44- search_to = 10 ,
45- )
46-
47- assert isinstance (response , XSOARSearchIncidentsResponse )
48- assert response .total == 1
49- assert len (response .data ) == 1
50- assert response .data [0 ].id == "1"
51- assert response .data [0 ].custom_fields .xdralerts [0 ].alert_id == "alert1"
52-
53- mock_post .assert_called_once ()
54- args , kwargs = mock_post .call_args
55- assert args [0 ] == "https://test.xsoar.com/xsoar/public/v1/incidents/search"
56- assert kwargs ["json" ]["filter" ]["size" ] == 10
57- assert kwargs ["json" ]["filter" ]["page" ] == 0
58- assert kwargs ["json" ]["filter" ]["fromDate" ] == "2023-01-01T00:00:00Z"
59- assert kwargs ["json" ]["filter" ]["toDate" ] == "2023-01-01T23:59:59Z"
60-
61-
62- def test_search_incidents_http_error (api_client ):
63- with patch ("requests.Session.post" ) as mock_post :
64- mock_post .return_value .raise_for_status .side_effect = (
65- requests .exceptions .HTTPError ("Error" )
66- )
67-
68- with pytest .raises (requests .exceptions .HTTPError ):
69- api_client .search_incidents ()
70-
71-
72- def test_search_incidents_pagination (api_client ):
73- with patch ("requests.Session.post" ) as mock_post :
74- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
75-
76- api_client .search_incidents (search_from = 20 , search_to = 30 )
77-
78- _ , kwargs = mock_post .call_args
79- assert kwargs ["json" ]["filter" ]["size" ] == 10
80- assert kwargs ["json" ]["filter" ]["page" ] == 2
81-
82-
83- # --- New tests ---
84-
85-
86- def test_search_incidents_no_dates (api_client ):
87- """When no dates are provided, fromDate and toDate are absent."""
88- with patch ("requests.Session.post" ) as mock_post :
89- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
90- api_client .search_incidents ()
91- _ , kwargs = mock_post .call_args
92- assert "fromDate" not in kwargs ["json" ]["filter" ]
93- assert "toDate" not in kwargs ["json" ]["filter" ]
94-
95-
96- def test_search_incidents_only_from_date (api_client ):
97- """When only from_date is provided, toDate is absent."""
98- with patch ("requests.Session.post" ) as mock_post :
99- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
100- api_client .search_incidents (from_date = "2026-01-01T00:00:00Z" )
101- _ , kwargs = mock_post .call_args
102- assert kwargs ["json" ]["filter" ]["fromDate" ] == "2026-01-01T00:00:00Z"
103- assert "toDate" not in kwargs ["json" ]["filter" ]
104-
105-
106- def test_search_incidents_only_to_date (api_client ):
107- """When only to_date is provided, fromDate is absent."""
108- with patch ("requests.Session.post" ) as mock_post :
109- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
110- api_client .search_incidents (to_date = "2026-12-31T23:59:59Z" )
111- _ , kwargs = mock_post .call_args
112- assert "fromDate" not in kwargs ["json" ]["filter" ]
113- assert kwargs ["json" ]["filter" ]["toDate" ] == "2026-12-31T23:59:59Z"
114-
115-
116- def test_search_incidents_zero_size (api_client ):
117- """When search_from == search_to, size is 0 and page is 0."""
118- with patch ("requests.Session.post" ) as mock_post :
119- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
120- api_client .search_incidents (search_from = 5 , search_to = 5 )
121- _ , kwargs = mock_post .call_args
122- assert kwargs ["json" ]["filter" ]["size" ] == 0
123- assert kwargs ["json" ]["filter" ]["page" ] == 0
124-
125-
126- def test_search_incidents_default_page_size (api_client ):
127- """Default search_from=0, search_to=100 gives size=100, page=0."""
128- with patch ("requests.Session.post" ) as mock_post :
129- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
130- api_client .search_incidents ()
131- _ , kwargs = mock_post .call_args
132- assert kwargs ["json" ]["filter" ]["size" ] == 100
133- assert kwargs ["json" ]["filter" ]["page" ] == 0
134-
135-
136- def test_search_incidents_headers_sent (api_client , auth ):
137- """Auth headers are included in the request."""
138- expected_headers = auth .get_headers ()
139- with patch ("requests.Session.post" ) as mock_post :
140- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
141- api_client .search_incidents ()
142- _ , kwargs = mock_post .call_args
143- assert kwargs ["headers" ] == expected_headers
144-
145-
146- def test_search_incidents_sort_order (api_client ):
147- """Request body always includes sort by 'created' ascending."""
148- with patch ("requests.Session.post" ) as mock_post :
149- mock_post .return_value .json .return_value = {"total" : 0 , "data" : []}
150- api_client .search_incidents ()
151- _ , kwargs = mock_post .call_args
152- assert kwargs ["json" ]["filter" ]["sort" ] == [{"field" : "created" , "asc" : True }]
153-
154-
155- def test_search_incidents_connection_error (api_client ):
156- """Connection errors propagate."""
157- with patch (
158- "requests.Session.post" ,
159- side_effect = requests .exceptions .ConnectionError ("no route" ),
160- ):
161- with pytest .raises (requests .exceptions .ConnectionError ):
162- api_client .search_incidents ()
163-
164-
165- def test_search_incidents_timeout (api_client ):
166- """Timeout errors propagate."""
167- with patch (
168- "requests.Session.post" , side_effect = requests .exceptions .Timeout ("timed out" )
169- ):
170- with pytest .raises (requests .exceptions .Timeout ):
171- api_client .search_incidents ()
172-
173-
174- def test_search_incidents_multiple_incidents (api_client ):
175- """Response with multiple incidents is parsed correctly."""
176- mock_response = {
177- "total" : 2 ,
178- "data" : [
179- {
180- "id" : "1" ,
181- "name" : "Inc 1" ,
182- "CustomFields" : {
183- "xdralerts" : [{"alert_id" : "a1" , "detection_timestamp" : 1000 }]
184- },
185- },
186- {
187- "id" : "2" ,
188- "name" : "Inc 2" ,
189- "CustomFields" : {
190- "xdralerts" : [{"alert_id" : "a2" , "detection_timestamp" : 2000 }]
191- },
192- },
193- ],
194- }
195- with patch ("requests.Session.post" ) as mock_post :
196- mock_post .return_value .json .return_value = mock_response
197- response = api_client .search_incidents ()
198- assert response .total == 2
199- assert len (response .data ) == 2
200- assert response .data [1 ].custom_fields .xdralerts [0 ].alert_id == "a2"
17+ def test_search_incidents_returns_valid_dummy_response (api_client ):
18+ response = api_client .search_incidents ()
19+
20+ assert isinstance (response , XSOARSearchIncidentsResponse )
21+ assert response .total == len (response .data )
22+ assert response .total >= 1
23+
24+ for incident in response .data :
25+ assert incident .id
26+ assert incident .custom_fields is not None
27+ assert len (incident .custom_fields .xdralerts ) == 1
28+ alert = incident .custom_fields .xdralerts [0 ]
29+ assert alert .alert_id
30+ assert isinstance (alert .detection_timestamp , int )
31+
32+
33+ def test_search_incidents_accepts_filters_without_external_calls (api_client ):
34+ response = api_client .search_incidents (
35+ from_date = "2026-01-01T00:00:00Z" ,
36+ to_date = "2026-01-01T23:59:59Z" ,
37+ search_from = 10 ,
38+ search_to = 20 ,
39+ )
40+
41+ assert isinstance (response , XSOARSearchIncidentsResponse )
42+ assert response .total == len (response .data )
43+
44+
45+ def test_search_incidents_can_be_forced_to_multiple_items (api_client , monkeypatch ):
46+ monkeypatch .setattr ("src.services.client_api.random.randint" , lambda a , b : 2 )
47+ response = api_client .search_incidents ()
48+ assert response .total == 2
49+ assert len (response .data ) == 2
50+
51+
52+ def test_search_incidents_generated_ids_are_unique (api_client ):
53+ response = api_client .search_incidents ()
54+ incident_ids = [incident .id for incident in response .data ]
55+ alert_ids = [
56+ incident .custom_fields .xdralerts [0 ].alert_id for incident in response .data
57+ ]
58+ assert len (set (incident_ids )) == len (incident_ids )
59+ assert len (set (alert_ids )) == len (alert_ids )
20160
20261
20362def test_api_client_stores_api_url ():
0 commit comments