1+ import json
2+
3+ import httpx
14import pytest
25from pytest_httpx import HTTPXMock
36from uipath .core .guardrails import (
@@ -43,7 +46,11 @@ def test_evaluate_guardrail_validation(
4346 httpx_mock .add_response (
4447 url = f"{ base_url } { org } { tenant } /agentsruntime_/api/execution/guardrails/validate" ,
4548 status_code = 200 ,
46- json = {"validation_passed" : True , "reason" : "Validation passed" },
49+ json = {
50+ "validation_passed" : True ,
51+ "reason" : "Validation passed" ,
52+ "skip" : False ,
53+ },
4754 )
4855
4956 # Create a PII detection guardrail
@@ -77,6 +84,11 @@ def test_evaluate_guardrail_validation(
7784
7885 assert result .validation_passed is True
7986 assert result .reason == "Validation passed"
87+ # If skip field exists, new API is deployed - check result and details
88+ if hasattr (result , "skip" ):
89+ assert result .skip is False
90+ assert result .result == "passed"
91+ assert result .details == "Validation passed"
8092
8193 def test_evaluate_guardrail_validation_failed (
8294 self ,
@@ -93,6 +105,7 @@ def test_evaluate_guardrail_validation_failed(
93105 json = {
94106 "validation_passed" : False ,
95107 "reason" : "PII detected: Email found" ,
108+ "skip" : False ,
96109 },
97110 )
98111
@@ -115,3 +128,201 @@ def test_evaluate_guardrail_validation_failed(
115128
116129 assert result .validation_passed is False
117130 assert result .reason == "PII detected: Email found"
131+ # If skip field exists, new API is deployed - check result and details
132+ if hasattr (result , "skip" ):
133+ assert result .skip is False
134+ assert result .result == "failed"
135+ assert result .details == "PII detected: Email found"
136+
137+ def test_evaluate_guardrail_entitlements_skip (
138+ self ,
139+ httpx_mock : HTTPXMock ,
140+ service : GuardrailsService ,
141+ base_url : str ,
142+ org : str ,
143+ tenant : str ,
144+ ) -> None :
145+ # Mock API response for entitlements check - feature disabled
146+ httpx_mock .add_response (
147+ url = f"{ base_url } { org } { tenant } /agentsruntime_/api/execution/guardrails/validate" ,
148+ status_code = 200 ,
149+ json = {
150+ "validation_passed" : True ,
151+ "reason" : "Guardrail feature is disabled" ,
152+ "skip" : True ,
153+ },
154+ )
155+
156+ pii_guardrail = BuiltInValidatorGuardrail (
157+ id = "test-id" ,
158+ name = "PII detection guardrail" ,
159+ description = "Test PII detection" ,
160+ enabled_for_evals = True ,
161+ selector = GuardrailSelector (
162+ scopes = [GuardrailScope .TOOL ], match_names = ["StringToNumber" ]
163+ ),
164+ guardrail_type = "builtInValidator" ,
165+ validator_type = "pii_detection" ,
166+ validator_parameters = [],
167+ )
168+
169+ test_input = "Contact me at john@example.com"
170+
171+ result = service .evaluate_guardrail (test_input , pii_guardrail )
172+
173+ assert result .validation_passed is True
174+ assert result .reason == "Guardrail feature is disabled"
175+ # If skip field exists, new API is deployed - check result and details
176+ if hasattr (result , "skip" ):
177+ assert result .skip is True
178+ assert result .result == "skipped"
179+ assert result .details == "Guardrail feature is disabled"
180+
181+ def test_evaluate_guardrail_entitlements_missing (
182+ self ,
183+ httpx_mock : HTTPXMock ,
184+ service : GuardrailsService ,
185+ base_url : str ,
186+ org : str ,
187+ tenant : str ,
188+ ) -> None :
189+ # Mock API response for entitlements check - entitlement missing
190+ httpx_mock .add_response (
191+ url = f"{ base_url } { org } { tenant } /agentsruntime_/api/execution/guardrails/validate" ,
192+ status_code = 200 ,
193+ json = {
194+ "validation_passed" : True ,
195+ "reason" : "Guardrail entitlement is missing" ,
196+ "skip" : True ,
197+ },
198+ )
199+
200+ pii_guardrail = BuiltInValidatorGuardrail (
201+ id = "test-id" ,
202+ name = "PII detection guardrail" ,
203+ description = "Test PII detection" ,
204+ enabled_for_evals = True ,
205+ selector = GuardrailSelector (
206+ scopes = [GuardrailScope .TOOL ], match_names = ["StringToNumber" ]
207+ ),
208+ guardrail_type = "builtInValidator" ,
209+ validator_type = "pii_detection" ,
210+ validator_parameters = [],
211+ )
212+
213+ test_input = "Contact me at john@example.com"
214+
215+ result = service .evaluate_guardrail (test_input , pii_guardrail )
216+
217+ assert result .validation_passed is True
218+ assert result .reason == "Guardrail entitlement is missing"
219+ # If skip field exists, new API is deployed - check result and details
220+ if hasattr (result , "skip" ):
221+ assert result .skip is True
222+ assert result .result == "skipped"
223+ assert result .details == "Guardrail entitlement is missing"
224+
225+ def test_evaluate_guardrail_request_payload_structure (
226+ self ,
227+ httpx_mock : HTTPXMock ,
228+ service : GuardrailsService ,
229+ base_url : str ,
230+ org : str ,
231+ tenant : str ,
232+ ) -> None :
233+ """Test that the request payload has the correct structure after revert."""
234+ captured_request = None
235+
236+ def capture_request (request ):
237+ nonlocal captured_request
238+ captured_request = request
239+ return httpx .Response (
240+ status_code = 200 ,
241+ json = {
242+ "validation_passed" : True ,
243+ "reason" : "Validation passed" ,
244+ "skip" : False ,
245+ },
246+ )
247+
248+ httpx_mock .add_callback (
249+ method = "POST" ,
250+ url = f"{ base_url } { org } { tenant } /agentsruntime_/api/execution/guardrails/validate" ,
251+ callback = capture_request ,
252+ )
253+
254+ # Create a PII detection guardrail with parameters
255+ pii_guardrail = BuiltInValidatorGuardrail (
256+ id = "test-id" ,
257+ name = "PII detection guardrail" ,
258+ description = "Test PII detection" ,
259+ enabled_for_evals = True ,
260+ selector = GuardrailSelector (
261+ scopes = [GuardrailScope .TOOL ], match_names = ["StringToNumber" ]
262+ ),
263+ guardrail_type = "builtInValidator" ,
264+ validator_type = "pii_detection" ,
265+ validator_parameters = [
266+ EnumListParameterValue (
267+ parameter_type = "enum-list" ,
268+ id = "entities" ,
269+ value = ["Email" , "Address" ],
270+ ),
271+ MapEnumParameterValue (
272+ parameter_type = "map-enum" ,
273+ id = "entityThresholds" ,
274+ value = {"Email" : 1 , "Address" : 0.7 },
275+ ),
276+ ],
277+ )
278+
279+ test_input = "There is no email or address here."
280+
281+ result = service .evaluate_guardrail (test_input , pii_guardrail )
282+
283+ # Verify the request was captured
284+ assert captured_request is not None
285+
286+ # Parse the request payload
287+ request_payload = json .loads (captured_request .content )
288+
289+ # Verify the payload structure matches the reverted format:
290+ # {
291+ # "validator": guardrail.validator_type,
292+ # "input": input_data,
293+ # "parameters": parameters,
294+ # }
295+ assert "validator" in request_payload
296+ assert "input" in request_payload
297+ assert "parameters" in request_payload
298+
299+ # Verify validator is a string (not an object)
300+ assert isinstance (request_payload ["validator" ], str )
301+ assert request_payload ["validator" ] == "pii_detection"
302+
303+ # Verify input is a string
304+ assert isinstance (request_payload ["input" ], str )
305+ assert request_payload ["input" ] == "There is no email or address here."
306+
307+ # Verify parameters is an array
308+ assert isinstance (request_payload ["parameters" ], list )
309+ assert len (request_payload ["parameters" ]) == 2
310+
311+ # Verify parameter structure
312+ entities_param = request_payload ["parameters" ][0 ]
313+ assert entities_param ["$parameterType" ] == "enum-list"
314+ assert entities_param ["id" ] == "entities"
315+ assert entities_param ["value" ] == ["Email" , "Address" ]
316+
317+ thresholds_param = request_payload ["parameters" ][1 ]
318+ assert thresholds_param ["$parameterType" ] == "map-enum"
319+ assert thresholds_param ["id" ] == "entityThresholds"
320+ assert thresholds_param ["value" ] == {"Email" : 1 , "Address" : 0.7 }
321+
322+ # Verify result fields
323+ assert result .validation_passed is True
324+ # If skip field exists, new API is deployed - check result and details
325+ if hasattr (result , "skip" ):
326+ assert result .skip is False
327+ assert result .result == "passed"
328+ assert result .details == "Validation passed"
0 commit comments