Skip to content

Commit a94ecdf

Browse files
feat: add tenant filtering to list instance methods for certificates, destinations, and fragments
1 parent 5143354 commit a94ecdf

7 files changed

Lines changed: 105 additions & 6 deletions

File tree

‎src/sap_cloud_sdk/destination/_local_client_base.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,20 @@ def find_provider() -> Optional[T]:
217217
return result
218218
return None
219219

220+
def _resolve_instance_list(
221+
self,
222+
tenant: Optional[str],
223+
instance_list: List[Dict[str, Any]],
224+
) -> List[T]:
225+
"""Resolve entities from the instance list filtered by tenant.
226+
227+
When tenant is provided, returns entries matching that tenant (subscriber context).
228+
When tenant is None, returns entries without a tenant field (provider context).
229+
"""
230+
if tenant is not None:
231+
return [self.from_dict(e) for e in instance_list if e.get("tenant") == tenant]
232+
return [self.from_dict(e) for e in instance_list if not e.get("tenant")]
233+
220234
def _resolve_subaccount_list(
221235
self,
222236
access_strategy: AccessStrategy,

‎src/sap_cloud_sdk/destination/local_certificate_client.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,9 @@ def list_instance_certificates(
253253
"""List all certificates from the service instance scope.
254254
255255
Args:
256-
tenant: Optional tenant subdomain (ignored in local dev mode).
256+
tenant: Optional subscriber tenant subdomain. When provided, returns only entries
257+
matching that tenant (subscriber context); otherwise returns provider-level
258+
entries (no tenant field).
257259
_filter: Optional ListCertificatesFilter (ignored in local dev mode).
258260
259261
Returns:
@@ -266,7 +268,7 @@ def list_instance_certificates(
266268
"""
267269
try:
268270
data = self._read()
269-
items = [Certificate.from_dict(entry) for entry in data.get("instance", [])]
271+
items = self._resolve_instance_list(tenant, data.get("instance", []))
270272
return PagedResult(items=items)
271273
except DestinationOperationError:
272274
raise

‎src/sap_cloud_sdk/destination/local_client.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class LocalDevDestinationClient(LocalDevClientBase[Destination]):
4141
],
4242
"instance": [
4343
{
44+
"tenant": "t1", # optional: subscriber-specific entry
4445
"name": "destC",
4546
"type": "HTTP",
4647
"url": "https://provider.example.com"
@@ -250,7 +251,9 @@ def list_instance_destinations(
250251
"""List all destinations from the service instance scope.
251252
252253
Args:
253-
tenant: Optional tenant subdomain (ignored in local dev mode).
254+
tenant: Optional subscriber tenant subdomain. When provided, returns only entries
255+
matching that tenant (subscriber context); otherwise returns provider-level
256+
entries (no tenant field).
254257
_filter: Optional ListDestinationsFilter (ignored in local dev mode).
255258
256259
Returns:
@@ -263,7 +266,7 @@ def list_instance_destinations(
263266
"""
264267
try:
265268
data = self._read()
266-
items = [Destination.from_dict(entry) for entry in data.get("instance", [])]
269+
items = self._resolve_instance_list(tenant, data.get("instance", []))
267270
return PagedResult(items=items)
268271
except DestinationOperationError:
269272
raise

‎src/sap_cloud_sdk/destination/local_fragment_client.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ def list_instance_fragments(
146146
"""List all fragments from the service instance scope.
147147
148148
Args:
149-
tenant: Optional tenant subdomain (ignored in local dev mode).
149+
tenant: Optional subscriber tenant subdomain. When provided, returns only entries
150+
matching that tenant (subscriber context); otherwise returns provider-level
151+
entries (no tenant field).
150152
151153
Returns:
152154
List of fragments. Returns empty list if no fragments exist.
@@ -156,7 +158,7 @@ def list_instance_fragments(
156158
"""
157159
try:
158160
data = self._read()
159-
return [Fragment.from_dict(entry) for entry in data.get("instance", [])]
161+
return self._resolve_instance_list(tenant, data.get("instance", []))
160162
except DestinationOperationError:
161163
raise
162164
except Exception as e:

‎tests/destination/unit/test_local_certificate_client.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,32 @@ def test_does_not_include_subaccount_entries(self, client):
143143
assert len(result.items) == 1
144144
assert result.items[0].name == "inst.pem"
145145

146+
def test_without_tenant_excludes_tenant_entries(self, client):
147+
_write_store(client, {"instance": [
148+
{"Name": "provider.pem", "Content": "c1"},
149+
{"Name": "subscriber.pem", "Content": "c2", "tenant": "t1"},
150+
], "subaccount": []})
151+
result = client.list_instance_certificates()
152+
assert len(result.items) == 1
153+
assert result.items[0].name == "provider.pem"
154+
155+
def test_with_tenant_returns_only_matching_entries(self, client):
156+
_write_store(client, {"instance": [
157+
{"Name": "provider.pem", "Content": "c1"},
158+
{"Name": "t1.pem", "Content": "c2", "tenant": "t1"},
159+
{"Name": "t2.pem", "Content": "c3", "tenant": "t2"},
160+
], "subaccount": []})
161+
result = client.list_instance_certificates(tenant="t1")
162+
assert len(result.items) == 1
163+
assert result.items[0].name == "t1.pem"
164+
165+
def test_with_tenant_returns_empty_when_no_match(self, client):
166+
_write_store(client, {"instance": [
167+
{"Name": "provider.pem", "Content": "c1"},
168+
], "subaccount": []})
169+
result = client.list_instance_certificates(tenant="unknown")
170+
assert len(result.items) == 0
171+
146172

147173
class TestListSubaccountCertificates:
148174
def test_returns_paged_result(self, client):

‎tests/destination/unit/test_local_destination_client.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,32 @@ def test_does_not_include_subaccount_entries(self, client):
164164
assert len(result.items) == 1
165165
assert result.items[0].name == "inst"
166166

167+
def test_without_tenant_excludes_tenant_entries(self, client):
168+
_write_store(client, {"instance": [
169+
{"name": "provider", "type": "HTTP"},
170+
{"name": "subscriber", "type": "HTTP", "tenant": "t1"},
171+
], "subaccount": []})
172+
result = client.list_instance_destinations()
173+
assert len(result.items) == 1
174+
assert result.items[0].name == "provider"
175+
176+
def test_with_tenant_returns_only_matching_entries(self, client):
177+
_write_store(client, {"instance": [
178+
{"name": "provider", "type": "HTTP"},
179+
{"name": "t1-dest", "type": "HTTP", "tenant": "t1"},
180+
{"name": "t2-dest", "type": "HTTP", "tenant": "t2"},
181+
], "subaccount": []})
182+
result = client.list_instance_destinations(tenant="t1")
183+
assert len(result.items) == 1
184+
assert result.items[0].name == "t1-dest"
185+
186+
def test_with_tenant_returns_empty_when_no_match(self, client):
187+
_write_store(client, {"instance": [
188+
{"name": "provider", "type": "HTTP"},
189+
], "subaccount": []})
190+
result = client.list_instance_destinations(tenant="unknown")
191+
assert len(result.items) == 0
192+
167193

168194
class TestListSubaccountDestinations:
169195
def test_returns_paged_result(self, client):

‎tests/destination/unit/test_local_fragment_client.py‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,32 @@ def test_does_not_include_subaccount_entries(self, client):
141141
assert len(result) == 1
142142
assert result[0].name == "inst"
143143

144+
def test_without_tenant_excludes_tenant_entries(self, client):
145+
_write_store(client, {"instance": [
146+
{"FragmentName": "provider", "URL": "https://a.com"},
147+
{"FragmentName": "subscriber", "URL": "https://b.com", "tenant": "t1"},
148+
], "subaccount": []})
149+
result = client.list_instance_fragments()
150+
assert len(result) == 1
151+
assert result[0].name == "provider"
152+
153+
def test_with_tenant_returns_only_matching_entries(self, client):
154+
_write_store(client, {"instance": [
155+
{"FragmentName": "provider", "URL": "https://a.com"},
156+
{"FragmentName": "t1-frag", "URL": "https://b.com", "tenant": "t1"},
157+
{"FragmentName": "t2-frag", "URL": "https://c.com", "tenant": "t2"},
158+
], "subaccount": []})
159+
result = client.list_instance_fragments(tenant="t1")
160+
assert len(result) == 1
161+
assert result[0].name == "t1-frag"
162+
163+
def test_with_tenant_returns_empty_when_no_match(self, client):
164+
_write_store(client, {"instance": [
165+
{"FragmentName": "provider", "URL": "https://a.com"},
166+
], "subaccount": []})
167+
result = client.list_instance_fragments(tenant="unknown")
168+
assert result == []
169+
144170

145171
class TestListSubaccountFragments:
146172
def test_returns_list_of_fragments(self, client):

0 commit comments

Comments
 (0)