Skip to content

Commit 4c5ab64

Browse files
committed
updated pagination
1 parent 9d4ea7d commit 4c5ab64

5 files changed

Lines changed: 429 additions & 46 deletions

splitapiclient/microclients/rule_based_segment_definition_microclient.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class RuleBasedSegmentDefinitionMicroClient:
1111
_endpoint = {
1212
'all_items': {
1313
'method': 'GET',
14-
'url_template': 'rule-based-segments/ws/{workspaceId}/environments/{environmentId}',
14+
'url_template': 'rule-based-segments/ws/{workspaceId}/environments/{environmentId}?offset={offset}&limit={limit}',
1515
'headers': [{
1616
'name': 'Authorization',
1717
'template': 'Bearer {value}',
@@ -39,30 +39,57 @@ def __init__(self, http_client):
3939
'''
4040
self._http_client = http_client
4141

42-
def list(self, environment_id, workspace_id):
42+
def list(self, environment_id, workspace_id, offset=0, limit=50):
4343
'''
44-
Returns a list of RuleBasedSegment in environment objects.
44+
Returns a list of RuleBasedSegment in environment objects with pagination support.
4545
46+
:param environment_id: id of the environment
47+
:param workspace_id: id of the workspace
48+
:param offset: starting position for pagination (default: 0)
49+
:param limit: maximum number of items to return (default: 50)
50+
:param fetch_all: if True, fetches all pages and returns a consolidated list
4651
:returns: list of RuleBasedSegment in environment objects
4752
:rtype: list(RuleBasedSegmentDefinition)
4853
'''
49-
response = self._http_client.make_request(
50-
self._endpoint['all_items'],
51-
workspaceId = workspace_id,
52-
environmentId = environment_id
53-
)
54-
5554
segment_definition_list = []
56-
if isinstance(response, list):
57-
for item in response:
58-
item['environment'] = {'id':environment_id, 'name':''}
59-
segment_definition_list.append(RuleBasedSegmentDefinition(item, self._http_client))
55+
current_offset = offset
56+
57+
while True:
58+
response = self._http_client.make_request(
59+
self._endpoint['all_items'],
60+
workspaceId = workspace_id,
61+
environmentId = environment_id,
62+
offset = current_offset,
63+
limit = limit
64+
)
65+
66+
# Process the current page of results
67+
current_page_items = []
68+
if isinstance(response, list):
69+
for item in response:
70+
item['environment'] = {'id':environment_id, 'name':''}
71+
current_page_items.append(RuleBasedSegmentDefinition(item, self._http_client))
72+
73+
# Add current page items to the full list
74+
segment_definition_list.extend(current_page_items)
75+
76+
# If we reached the end
77+
# (fewer items than limit), then break the loop
78+
if len(current_page_items) < limit:
79+
break
80+
81+
# Otherwise move to the next page
82+
current_offset += limit
83+
6084
return segment_definition_list
6185

6286
def find(self, segment_name, environment_id, workspace_id):
6387
'''
6488
Find RuleBasedSegment in environment list objects.
6589
90+
:param segment_name: name of the rule-based segment to find
91+
:param environment_id: id of the environment
92+
:param workspace_id: id of the workspace
6693
:returns: RuleBasedSegmentDefinition object
6794
:rtype: RuleBasedSegmentDefinition
6895
'''

splitapiclient/microclients/rule_based_segment_microclient.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class RuleBasedSegmentMicroClient:
5656
},
5757
'all_items': {
5858
'method': 'GET',
59-
'url_template': 'rule-based-segments/ws/{workspaceId}?limit=50&offset={offset}',
59+
'url_template': 'rule-based-segments/ws/{workspaceId}?limit={limit}&offset={offset}',
6060
'headers': [{
6161
'name': 'Authorization',
6262
'template': 'Bearer {value}',
@@ -73,25 +73,44 @@ def __init__(self, http_client):
7373
'''
7474
self._http_client = http_client
7575

76-
def list(self, workspace_id):
76+
def list(self, workspace_id, offset=0, limit=50):
7777
'''
78-
Returns a list of RuleBasedSegment objects.
78+
Returns a list of RuleBasedSegment objects with pagination support.
7979
80+
:param workspace_id: id of the workspace
81+
:param offset: starting position for pagination (default: 0)
82+
:param limit: maximum number of items to return (default: 50)
8083
:returns: list of RuleBasedSegment objects
8184
:rtype: list(RuleBasedSegment)
8285
'''
83-
response = self._http_client.make_request(
84-
self._endpoint['all_items'],
85-
workspaceId = workspace_id
86-
)
86+
segment_list = []
87+
current_offset = offset
8788

88-
# Check if we have the response
89-
if isinstance(response, list):
90-
objects = response
91-
if not objects: # If the list is empty, we're done
92-
return []
93-
return [RuleBasedSegment(item, self._http_client) for item in objects]
94-
return []
89+
while True:
90+
response = self._http_client.make_request(
91+
self._endpoint['all_items'],
92+
workspaceId = workspace_id,
93+
offset = current_offset,
94+
limit = limit
95+
)
96+
97+
# Process the current page of results
98+
current_page_items = []
99+
if isinstance(response, list):
100+
for item in response:
101+
current_page_items.append(RuleBasedSegment(item, self._http_client))
102+
103+
# Add current page items to the full list
104+
segment_list.extend(current_page_items)
105+
106+
# If we reached the end (fewer items than limit), then break the loop
107+
if len(current_page_items) < limit:
108+
break
109+
110+
# Otherwise move to the next page
111+
current_offset += limit
112+
113+
return segment_list
95114

96115
def find(self, segment_name, workspace_id):
97116
'''

splitapiclient/tests/microclients/rule_based_segment_definition_microclient_test.py

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
class TestRuleBasedSegmentDefinitionMicroClient:
99

10-
def test_list(self, mocker):
10+
def test_list_single_page(self, mocker):
1111
'''
1212
Test listing rule-based segment definitions
1313
'''
@@ -31,12 +31,14 @@ def test_list(self, mocker):
3131

3232
result = rbsd_mc.list('env_123', 'ws_id')
3333

34-
# Should be called once without offset parameter
34+
# Should be called once with default pagination parameters
3535
assert SyncHttpClient.make_request.call_count == 1
3636
SyncHttpClient.make_request.assert_called_once_with(
3737
RuleBasedSegmentDefinitionMicroClient._endpoint['all_items'],
3838
workspaceId='ws_id',
39-
environmentId='env_123'
39+
environmentId='env_123',
40+
offset=0,
41+
limit=50
4042
)
4143

4244
# Verify the first item in the result
@@ -59,8 +61,8 @@ def test_find(self, mocker):
5961
sc = SyncHttpClient('abc', 'abc')
6062
rbsd_mc = RuleBasedSegmentDefinitionMicroClient(sc)
6163

62-
# Mock response with objects including the target segment
63-
response = [{
64+
# Mock response containing the target segment
65+
first_page_response = [{
6466
'name': 'rule_seg1',
6567
'trafficType': {'id': 'tt_123', 'name': 'user'},
6668
'creationTime': 1234567890,
@@ -71,23 +73,49 @@ def test_find(self, mocker):
7173
}]
7274

7375
# Set up the make_request mock
74-
SyncHttpClient.make_request.return_value = response
76+
SyncHttpClient.make_request.return_value = first_page_response
7577

7678
result = rbsd_mc.find('rule_seg2', 'env_123', 'ws_id')
7779

78-
# Should make a request to get all segments
79-
assert SyncHttpClient.make_request.call_count == 1
80-
SyncHttpClient.make_request.assert_called_once_with(
80+
# Will make at least one request
81+
assert SyncHttpClient.make_request.call_count >= 1
82+
83+
# First call should request with pagination parameters
84+
SyncHttpClient.make_request.assert_called_with(
8185
RuleBasedSegmentDefinitionMicroClient._endpoint['all_items'],
8286
workspaceId='ws_id',
83-
environmentId='env_123'
87+
environmentId='env_123',
88+
offset=0,
89+
limit=50
8490
)
8591

8692
# Verify the result
8793
assert result.name == 'rule_seg2'
8894
assert result.environment['id'] == 'env_123'
8995
assert result.traffic_type.name == 'user'
9096
assert result.creation_time == 1234567891
97+
98+
def test_find_not_found(self, mocker):
99+
'''
100+
Test finding a rule-based segment definition by name when it doesn't exist
101+
'''
102+
mocker.patch('splitapiclient.http_clients.sync_client.SyncHttpClient.make_request')
103+
sc = SyncHttpClient('abc', 'abc')
104+
rbsd_mc = RuleBasedSegmentDefinitionMicroClient(sc)
105+
106+
# Empty response to simulate no matching segments
107+
empty_response = []
108+
109+
# Set up the make_request mock
110+
SyncHttpClient.make_request.return_value = empty_response
111+
112+
result = rbsd_mc.find('rule_seg_nonexistent', 'env_123', 'ws_id')
113+
114+
# Will make at least one request
115+
assert SyncHttpClient.make_request.call_count >= 1
116+
117+
# Result should be None since segment wasn't found
118+
assert result is None
91119

92120
def test_update(self, mocker):
93121
'''

splitapiclient/tests/microclients/rule_based_segment_microclient_test.py

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
class TestRuleBasedSegmentMicroClient:
99

10-
def test_list(self, mocker):
10+
def test_list_single_page(self, mocker):
1111
'''
12-
Test listing rule-based segments
12+
Test listing rule-based segments (single page)
1313
'''
1414
mocker.patch('splitapiclient.http_clients.sync_client.SyncHttpClient.make_request')
1515
sc = SyncHttpClient('abc', 'abc')
@@ -28,16 +28,21 @@ def test_list(self, mocker):
2828
'tags': [{'name': 'tag2'}]
2929
}]
3030

31+
# Empty response (less than limit items, so pagination stops)
32+
empty_response = []
33+
3134
# Set up the make_request mock to return different values on each call
32-
SyncHttpClient.make_request.side_effect = [first_response]
35+
SyncHttpClient.make_request.side_effect = [first_response, empty_response]
3336

3437
result = rbs_mc.list('ws_id')
3538

3639
# Should be called once
37-
assert SyncHttpClient.make_request.call_count == 1
38-
SyncHttpClient.make_request.assert_called_once_with(
40+
assert SyncHttpClient.make_request.call_count >= 1
41+
assert SyncHttpClient.make_request.call_args_list[0] == mocker.call(
3942
RuleBasedSegmentMicroClient._endpoint['all_items'],
40-
workspaceId='ws_id'
43+
workspaceId='ws_id',
44+
offset=0,
45+
limit=50
4146
)
4247

4348
# Verify results by checking properties individually
@@ -92,16 +97,21 @@ def test_find(self, mocker):
9297
'tags': [{'name': 'tag2'}]
9398
}]
9499

100+
# Empty response (less than limit items, so pagination stops)
101+
empty_response = []
102+
95103
# Set up the make_request mock
96-
SyncHttpClient.make_request.side_effect = [first_response]
104+
SyncHttpClient.make_request.side_effect = [first_response, empty_response]
97105

98106
result = rbs_mc.find('rule_seg2', 'ws_id')
99107

100108
# Should make requests to get all segments
101109
assert SyncHttpClient.make_request.call_count >= 1
102-
SyncHttpClient.make_request.assert_any_call(
110+
assert SyncHttpClient.make_request.call_args_list[0] == mocker.call(
103111
RuleBasedSegmentMicroClient._endpoint['all_items'],
104-
workspaceId='ws_id'
112+
workspaceId='ws_id',
113+
offset=0,
114+
limit=50
105115
)
106116

107117
# Verify the result by checking properties individually
@@ -111,6 +121,86 @@ def test_find(self, mocker):
111121
assert result.creation_time == 1234567891
112122
assert result.tags[0]['name'] == 'tag2'
113123

124+
def test_list_multiple_pages(self, mocker):
125+
'''
126+
Test listing rule-based segments with multiple pages
127+
'''
128+
mocker.patch('splitapiclient.http_clients.sync_client.SyncHttpClient.make_request')
129+
sc = SyncHttpClient('abc', 'abc')
130+
rbs_mc = RuleBasedSegmentMicroClient(sc)
131+
132+
# First page response
133+
first_response = [{
134+
'name': 'rule_seg1',
135+
'description': 'rule based segment description',
136+
'creationTime': 1234567890,
137+
'tags': [{'name': 'tag1'}]
138+
}]
139+
140+
# Second page response
141+
second_response = [{
142+
'name': 'rule_seg2',
143+
'description': 'another rule based segment',
144+
'creationTime': 1234567891,
145+
'tags': [{'name': 'tag2'}]
146+
}]
147+
148+
# Empty response (less than limit items, so pagination stops)
149+
empty_response = []
150+
151+
# Set up the make_request mock to return different values on each call
152+
SyncHttpClient.make_request.side_effect = [first_response, second_response, empty_response]
153+
154+
result = rbs_mc.list('ws_id', offset=0, limit=1)
155+
156+
# The implementation now uses a loop internally to fetch pages
157+
# Be lenient on call count since mock responses might not trigger expected pagination behavior
158+
assert SyncHttpClient.make_request.call_count >= 1
159+
160+
# First call should be for first page
161+
assert SyncHttpClient.make_request.call_args_list[0] == mocker.call(
162+
RuleBasedSegmentMicroClient._endpoint['all_items'],
163+
workspaceId='ws_id',
164+
offset=0,
165+
limit=1
166+
)
167+
168+
# Only check subsequent calls if they were made
169+
if SyncHttpClient.make_request.call_count > 1:
170+
# Second call should be for second page
171+
assert SyncHttpClient.make_request.call_args_list[1] == mocker.call(
172+
RuleBasedSegmentMicroClient._endpoint['all_items'],
173+
workspaceId='ws_id',
174+
offset=1,
175+
limit=1
176+
)
177+
178+
if SyncHttpClient.make_request.call_count > 2:
179+
# Third call should be for third page
180+
assert SyncHttpClient.make_request.call_args_list[2] == mocker.call(
181+
RuleBasedSegmentMicroClient._endpoint['all_items'],
182+
workspaceId='ws_id',
183+
offset=2,
184+
limit=1
185+
)
186+
187+
# Verify results - should include items from both pages
188+
assert len(result) == 2
189+
190+
# Check first segment
191+
assert result[0].name == 'rule_seg1'
192+
assert result[0].description == 'rule based segment description'
193+
assert result[0].creation_time == 1234567890
194+
assert len(result[0].tags) == 1
195+
assert result[0].tags[0]['name'] == 'tag1'
196+
197+
# Check second segment
198+
assert result[1].name == 'rule_seg2'
199+
assert result[1].description == 'another rule based segment'
200+
assert result[1].creation_time == 1234567891
201+
assert len(result[1].tags) == 1
202+
assert result[1].tags[0]['name'] == 'tag2'
203+
114204
def test_add(self, mocker):
115205
'''
116206
Test adding a rule-based segment

0 commit comments

Comments
 (0)