|
18 | 18 | from litellm.proxy.management_endpoints.scim.scim_transformations import (
|
19 | 19 | ScimTransformations,
|
20 | 20 | )
|
21 |
| -from litellm.types.proxy.management_endpoints.scim_v2 import SCIMGroup, SCIMUser |
| 21 | +from litellm.types.proxy.management_endpoints.scim_v2 import ( |
| 22 | + SCIMGroup, |
| 23 | + SCIMPatchOp, |
| 24 | + SCIMPatchOperation, |
| 25 | + SCIMUser, |
| 26 | +) |
22 | 27 |
|
23 | 28 |
|
24 | 29 | # Mock data
|
@@ -223,3 +228,58 @@ def test_get_scim_member_value(self):
|
223 | 228 | member_without_email = Member(user_id="user-456", user_email=None, role="user")
|
224 | 229 | result = ScimTransformations._get_scim_member_value(member_without_email)
|
225 | 230 | assert result == ScimTransformations.DEFAULT_SCIM_MEMBER_VALUE
|
| 231 | + |
| 232 | + |
| 233 | +class TestSCIMPatchOperations: |
| 234 | + """Test SCIM PATCH operation validation and case-insensitive handling""" |
| 235 | + |
| 236 | + def test_scim_patch_operation_lowercase(self): |
| 237 | + """Test that lowercase operations are accepted""" |
| 238 | + op = SCIMPatchOperation(op="add", path="members", value=[{"value": "user123"}]) |
| 239 | + assert op.op == "add" |
| 240 | + |
| 241 | + op = SCIMPatchOperation(op="remove", path='members[value eq "user123"]') |
| 242 | + assert op.op == "remove" |
| 243 | + |
| 244 | + op = SCIMPatchOperation(op="replace", path="displayName", value="New Name") |
| 245 | + assert op.op == "replace" |
| 246 | + |
| 247 | + def test_scim_patch_operation_uppercase(self): |
| 248 | + """Test that uppercase operations are normalized to lowercase""" |
| 249 | + op = SCIMPatchOperation(op="ADD", path="members", value=[{"value": "user123"}]) |
| 250 | + assert op.op == "add" |
| 251 | + |
| 252 | + op = SCIMPatchOperation(op="REMOVE", path='members[value eq "user123"]') |
| 253 | + assert op.op == "remove" |
| 254 | + |
| 255 | + op = SCIMPatchOperation(op="REPLACE", path="displayName", value="New Name") |
| 256 | + assert op.op == "replace" |
| 257 | + |
| 258 | + def test_scim_patch_operation_mixed_case(self): |
| 259 | + """Test that mixed case operations are normalized to lowercase""" |
| 260 | + op = SCIMPatchOperation(op="Add", path="members", value=[{"value": "user123"}]) |
| 261 | + assert op.op == "add" |
| 262 | + |
| 263 | + op = SCIMPatchOperation(op="Remove", path='members[value eq "user123"]') |
| 264 | + assert op.op == "remove" |
| 265 | + |
| 266 | + op = SCIMPatchOperation(op="Replace", path="displayName", value="New Name") |
| 267 | + assert op.op == "replace" |
| 268 | + |
| 269 | + def test_scim_patch_operation_with_optional_fields(self): |
| 270 | + """Test SCIMPatchOperation with and without optional fields""" |
| 271 | + # Operation with all fields |
| 272 | + op_full = SCIMPatchOperation( |
| 273 | + op="Add", |
| 274 | + path="members", |
| 275 | + value=[{"value": "user123", "display": "User 123"}], |
| 276 | + ) |
| 277 | + assert op_full.op == "add" |
| 278 | + assert op_full.path == "members" |
| 279 | + assert op_full.value == [{"value": "user123", "display": "User 123"}] |
| 280 | + |
| 281 | + # Operation with minimal fields (only op is required) |
| 282 | + op_minimal = SCIMPatchOperation(op="Remove") |
| 283 | + assert op_minimal.op == "remove" |
| 284 | + assert op_minimal.path is None |
| 285 | + assert op_minimal.value is None |
0 commit comments