@@ -104,6 +104,61 @@ def testVerifySslDisabled(self):
104104 mock_conn .setopt .assert_any_call (pycurl .SSL_VERIFYPEER , 0 )
105105 mock_conn .setopt .assert_any_call (pycurl .SSL_VERIFYHOST , 0 )
106106
107+ def testBuildUrlWithParameters (self ):
108+ """Test that URL parameters are properly handled."""
109+ config = {
110+ "base_url" : "https://api.example.com/scim" ,
111+ "auth_token" : "test_token"
112+ }
113+ source = scimsource .ScimSource (config )
114+
115+ # Test with no parameters
116+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Users" , "" )
117+ self .assertEqual (url , "https://api.example.com/scim/Users" )
118+
119+ # Test with simple parameters (comma gets URL encoded)
120+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Users" , "groups=users,admin" )
121+ self .assertEqual (url , "https://api.example.com/scim/Users?groups=users%2Cadmin" )
122+
123+ # Test with parameters that have leading ? or &
124+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Users" , "?groups=users,admin" )
125+ self .assertEqual (url , "https://api.example.com/scim/Users?groups=users%2Cadmin" )
126+
127+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Users" , "&groups=users,admin" )
128+ self .assertEqual (url , "https://api.example.com/scim/Users?groups=users%2Cadmin" )
129+
130+ # Test with complex SCIM filter that needs encoding
131+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Groups" , 'filter=displayName eq "users"' )
132+ self .assertEqual (url , "https://api.example.com/scim/Groups?filter=displayName+eq+%22users%22" )
133+
134+ # Test with multiple parameters
135+ url = source ._BuildUrlWithParameters ("https://api.example.com/scim/Users" , "groups=admin,metrics&filter=active eq \" true\" " )
136+ self .assertEqual (url , "https://api.example.com/scim/Users?groups=admin%2Cmetrics&filter=active+eq+%22true%22" )
137+
138+ def testParametersConfiguration (self ):
139+ """Test that users_parameters and groups_parameters are configured properly."""
140+ config = {
141+ "base_url" : "https://api.example.com/scim" ,
142+ "auth_token" : "test_token" ,
143+ "users_parameters" : "groups=users,admin&filter=active" ,
144+ "groups_parameters" : "type=security"
145+ }
146+ source = scimsource .ScimSource (config )
147+
148+ self .assertEqual (source .conf ["users_parameters" ], "groups=users,admin&filter=active" )
149+ self .assertEqual (source .conf ["groups_parameters" ], "type=security" )
150+
151+ def testParametersDefaultsToEmpty (self ):
152+ """Test that parameters default to empty strings."""
153+ config = {
154+ "base_url" : "https://api.example.com/scim" ,
155+ "auth_token" : "test_token"
156+ }
157+ source = scimsource .ScimSource (config )
158+
159+ self .assertEqual (source .conf ["users_parameters" ], "" )
160+ self .assertEqual (source .conf ["groups_parameters" ], "" )
161+
107162
108163class TestScimUpdateGetter (unittest .TestCase ):
109164 def setUp (self ):
@@ -203,6 +258,103 @@ def mock_get_map(cache_info, data):
203258 self .assertIn ("Users" , call_args [0 ][0 ][0 ]) # First call should be to base URL
204259 self .assertIn ("startIndex=51" , call_args [1 ][0 ][0 ]) # Second call should have pagination
205260
261+ def testGetUpdatesWithPaginationAndCustomParameters (self ):
262+ """Test that pagination works correctly with custom URL parameters."""
263+ mock_conn = mock .Mock ()
264+ mock_conn .getinfo .return_value = 200
265+ self .curl_mock .return_value = mock_conn
266+
267+ config = {
268+ "base_url" : "https://api.example.com/scim" ,
269+ "auth_token" : "test_token"
270+ }
271+ source = scimsource .ScimSource (config )
272+
273+ # Mock the first page response with pagination info
274+ first_page_response = {
275+ "totalResults" : 75 ,
276+ "itemsPerPage" : 50 ,
277+ "startIndex" : 1 ,
278+ "Resources" : [{"id" : str (i ), "userName" : f"user{ i } " } for i in range (1 , 51 )]
279+ }
280+
281+ # Mock the second page response
282+ second_page_response = {
283+ "totalResults" : 75 ,
284+ "itemsPerPage" : 25 ,
285+ "startIndex" : 51 ,
286+ "Resources" : [{"id" : str (i ), "userName" : f"user{ i } " } for i in range (51 , 76 )]
287+ }
288+
289+ with mock .patch .object (curl , 'CurlFetch' ) as mock_curl_fetch :
290+ mock_curl_fetch .side_effect = [
291+ (200 , "" , json .dumps (first_page_response ).encode ('utf-8' )),
292+ (200 , "" , json .dumps (second_page_response ).encode ('utf-8' ))
293+ ]
294+
295+ getter = scimsource .UpdateGetter ()
296+ getter .source = source
297+
298+ # Mock the parser and its pagination metadata
299+ mock_parser = mock .Mock ()
300+
301+ # Mock the first map returned by GetMap
302+ mock_first_map = mock .Mock ()
303+ mock_first_map .__len__ = mock .Mock (return_value = 50 )
304+
305+ # Mock the second map returned by GetMap
306+ mock_second_map = mock .Mock ()
307+ mock_second_map .__len__ = mock .Mock (return_value = 75 ) # Total items after both pages
308+
309+ # Track which call we're on
310+ call_count = 0
311+
312+ # Configure GetMap to return the mocked maps and update pagination metadata
313+ def mock_get_map (cache_info , data ):
314+ nonlocal call_count
315+ call_count += 1
316+
317+ if call_count == 1 :
318+ # First page
319+ mock_parser ._pagination_metadata = {
320+ 'totalResults' : 75 ,
321+ 'itemsPerPage' : 50 ,
322+ 'startIndex' : 1
323+ }
324+ return mock_first_map
325+ else :
326+ # Second page
327+ mock_parser ._pagination_metadata = {
328+ 'totalResults' : 75 ,
329+ 'itemsPerPage' : 25 ,
330+ 'startIndex' : 51
331+ }
332+ return mock_second_map
333+
334+ mock_parser .GetMap = mock .Mock (side_effect = mock_get_map )
335+
336+ getter .GetParser = mock .Mock (return_value = mock_parser )
337+ getter .CreateMap = mock .Mock (return_value = mock .Mock ())
338+
339+ # Test with URL that has custom parameters
340+ result = getter .GetUpdates (source , "https://api.example.com/scim/Users?groups=users,admin" , None )
341+
342+ # Should call CurlFetch twice (first page + second page)
343+ self .assertEqual (mock_curl_fetch .call_count , 2 )
344+
345+ # Should call GetMap twice (first page + second page)
346+ self .assertEqual (mock_parser .GetMap .call_count , 2 )
347+
348+ # Verify the URLs include both custom parameters and pagination parameters
349+ call_args = mock_curl_fetch .call_args_list
350+ # First call should include custom parameters and startIndex=1
351+ self .assertIn ("groups=users,admin" , call_args [0 ][0 ][0 ])
352+ self .assertIn ("startIndex=1" , call_args [0 ][0 ][0 ])
353+
354+ # Second call should include custom parameters and startIndex=51
355+ self .assertIn ("groups=users,admin" , call_args [1 ][0 ][0 ])
356+ self .assertIn ("startIndex=51" , call_args [1 ][0 ][0 ])
357+
206358
207359class TestScimPasswdUpdateGetter (unittest .TestCase ):
208360 def setUp (self ):
0 commit comments