11from typing import Any
22
3- from scim2_client .engines .httpx2 import SyncSCIMClient
3+ from scim2_client import BaseSyncSCIMClient
4+ from scim2_models import ScimProvider
5+ from scim2_models import ScimProviderError
46
57from scim2_tester .checkers import random_url
68from scim2_tester .checkers import resource_type_tests
1113from scim2_tester .utils import CheckContext
1214from scim2_tester .utils import CheckResult
1315from scim2_tester .utils import Status
16+ from scim2_tester .utils import check_result
1417
1518
1619def _discovered_objects (results : list [CheckResult ]) -> Any :
@@ -23,8 +26,56 @@ def _discovered_objects(results: list[CheckResult]) -> Any:
2326 return results [0 ].data if results [0 ].status == Status .SUCCESS else None
2427
2528
29+ def _describe_service (
30+ context : CheckContext ,
31+ results_spc : list [CheckResult ],
32+ results_resource_types : list [CheckResult ],
33+ results_schemas : list [CheckResult ],
34+ ) -> tuple [ScimProvider | None , list [CheckResult ]]:
35+ """Compose the description of the server from what its discovery endpoints published.
36+
37+ What the client already describes wins over what the server publishes, as
38+ :meth:`~scim2_client.BaseSyncSCIMClient.discover` does. The description is
39+ registered on the client so the remaining checks are run against it.
40+ """
41+ provider = context .client .provider
42+ config = provider .config or _discovered_objects (results_spc )
43+
44+ if provider .models :
45+ described = ScimProvider (
46+ provider .models , provider .resource_types , config , provider .policy
47+ )
48+ context .client .provider = described
49+ return described , []
50+
51+ resource_types = _discovered_objects (results_resource_types )
52+ schemas = _discovered_objects (results_schemas )
53+ if not resource_types or not schemas :
54+ return None , []
55+
56+ try :
57+ described = ScimProvider .from_discovery (
58+ schemas , resource_types , config , provider .policy
59+ )
60+ except ScimProviderError as exc :
61+ return None , [
62+ check_result (
63+ context ,
64+ status = Status .ERROR ,
65+ title = "service_description" ,
66+ description = "Compose the resource models the server serves from "
67+ "the schemas and the resource types it publishes." ,
68+ reason = str (exc ),
69+ tags = {"discovery" },
70+ )
71+ ]
72+
73+ context .client .provider = described
74+ return described , []
75+
76+
2677def check_server (
27- client : SyncSCIMClient ,
78+ client : BaseSyncSCIMClient ,
2879 raise_exceptions : bool = False ,
2980 include_tags : set [str ] | None = None ,
3081 exclude_tags : set [str ] | None = None ,
@@ -34,7 +85,8 @@ def check_server(
3485
3586 It starts by retrieving the standard :class:`~scim2_models.ServiceProviderConfig`,
3687 :class:`~scim2_models.Schema` and :class:`~scim2_models.ResourceType` endpoints.
37- Those configuration resources will be registered to the client if no other have been registered yet.
88+ What they publish describes the server as a :class:`~scim2_models.ScimProvider`
89+ registered on the client, leaving untouched whatever the client already described.
3890
3991 Then for all available resources (whether they have been manually configured in the client,
4092 or dynamically discovered by the checker), it perform a series of creation, query, replacement and deletion.
@@ -86,33 +138,25 @@ def check_server(
86138
87139 results_spc = service_provider_config_endpoint (context )
88140 results .extend (results_spc )
89- if not client .service_provider_config :
90- client .service_provider_config = _discovered_objects (results_spc )
91141
92142 results_resource_types = _resource_types_endpoint (context )
93143 results .extend (results_resource_types )
94- if not client .resource_types :
95- client .resource_types = _discovered_objects (results_resource_types )
96144
97145 results_schemas = _schemas_endpoint (context )
98146 results .extend (results_schemas )
99- schemas = _discovered_objects (results_schemas )
100- if not client .resource_models and schemas :
101- client .resource_models = client .build_resource_models (
102- client .resource_types or [], schemas
103- )
104147
105- if (
106- not client .service_provider_config
107- or not client .resource_types
108- or not client .resource_models
109- ):
148+ provider , results_description = _describe_service (
149+ context , results_spc , results_resource_types , results_schemas
150+ )
151+ results .extend (results_description )
152+
153+ if provider is None or not provider .config :
110154 return results
111155
112156 result_random = random_url (context )
113157 results .extend (result_random )
114158
115- for resource_type in client .resource_types or [] :
159+ for resource_type in provider .resource_types :
116160 if conf .resource_types and resource_type .name not in conf .resource_types :
117161 continue
118162
0 commit comments