Skip to content

Commit 673e119

Browse files
committed
feat: implement additional tests on the core resources
1 parent 83e1476 commit 673e119

9 files changed

Lines changed: 345 additions & 67 deletions

File tree

scim2_tester/checker.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
from scim2_tester.checkers import random_url
66
from scim2_tester.checkers import resource_type_tests
7-
from scim2_tester.checkers import resource_types_endpoint
8-
from scim2_tester.checkers import schemas_endpoint
97
from scim2_tester.checkers import service_provider_config_endpoint
8+
from scim2_tester.checkers.resource_types import _resource_types_endpoint
9+
from scim2_tester.checkers.schemas import _schemas_endpoint
1010
from scim2_tester.utils import CheckConfig
1111
from scim2_tester.utils import CheckContext
1212
from scim2_tester.utils import CheckResult
@@ -80,7 +80,7 @@ def check_server(
8080
if result_spc.status != Status.SKIPPED and not client.service_provider_config:
8181
client.service_provider_config = result_spc.data
8282

83-
results_resource_types = resource_types_endpoint(context)
83+
results_resource_types = _resource_types_endpoint(context)
8484
results.extend(results_resource_types)
8585
if not client.resource_types:
8686
# Find first non-skipped result with data
@@ -89,7 +89,7 @@ def check_server(
8989
client.resource_types = rt_result.data
9090
break
9191

92-
results_schemas = schemas_endpoint(context)
92+
results_schemas = _schemas_endpoint(context)
9393
results.extend(results_schemas)
9494
if not client.resource_models:
9595
# Find first non-skipped result with data

scim2_tester/checkers/__init__.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,30 @@
2020
from .resource_types import access_invalid_resource_type
2121
from .resource_types import query_all_resource_types
2222
from .resource_types import query_resource_type_by_id
23-
from .resource_types import resource_types_endpoint
23+
from .resource_types import resource_types_endpoint_methods
24+
from .resource_types import resource_types_schema_validation
2425
from .schemas import access_invalid_schema
26+
from .schemas import access_schema_by_id
27+
from .schemas import core_schemas_validation
2528
from .schemas import query_all_schemas
26-
from .schemas import query_schema_by_id
27-
from .schemas import schemas_endpoint
29+
from .schemas import schemas_endpoint_methods
2830
from .service_provider_config import service_provider_config_endpoint
31+
from .service_provider_config import service_provider_config_endpoint_methods
2932

3033
__all__ = [
3134
# Discovery checkers
3235
"service_provider_config_endpoint",
33-
"resource_types_endpoint",
36+
"service_provider_config_endpoint_methods",
37+
"resource_types_endpoint_methods",
38+
"resource_types_schema_validation",
3439
"query_all_resource_types",
3540
"query_resource_type_by_id",
3641
"access_invalid_resource_type",
37-
"schemas_endpoint",
42+
"schemas_endpoint_methods",
3843
"query_all_schemas",
39-
"query_schema_by_id",
44+
"access_schema_by_id",
4045
"access_invalid_schema",
46+
"core_schemas_validation",
4147
# CRUD checkers
4248
"object_creation",
4349
"object_query",
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Utility functions for discovery endpoint testing."""
2+
3+
from scim2_client import SCIMClientError
4+
5+
from ..utils import CheckContext
6+
from ..utils import CheckResult
7+
from ..utils import Status
8+
9+
10+
def _test_discovery_endpoint_methods(
11+
context: CheckContext, endpoint: str
12+
) -> list[CheckResult]:
13+
"""Test that unsupported HTTP methods return 405 Method Not Allowed.
14+
15+
Tests that POST, PUT, PATCH, and DELETE methods on the specified discovery
16+
endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported.
17+
18+
**Status:**
19+
20+
- :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status
21+
- :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status
22+
23+
.. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>`
24+
25+
Discovery endpoints only support GET method. Other HTTP methods
26+
should return appropriate error responses.
27+
"""
28+
results = []
29+
methods = ["POST", "PUT", "PATCH", "DELETE"]
30+
31+
for method in methods:
32+
try:
33+
# Use underlying httpx client to test different HTTP methods
34+
response = context.client.client.request(
35+
method=method,
36+
url=endpoint,
37+
)
38+
if response.status_code == 405:
39+
results.append(
40+
CheckResult(
41+
status=Status.SUCCESS,
42+
reason=f"{method} {endpoint} correctly returned 405 Method Not Allowed",
43+
data=response,
44+
)
45+
)
46+
else:
47+
results.append(
48+
CheckResult(
49+
status=Status.ERROR,
50+
reason=f"{method} {endpoint} returned {response.status_code} instead of 405",
51+
data=response,
52+
)
53+
)
54+
except SCIMClientError as e:
55+
results.append(
56+
CheckResult(
57+
status=Status.ERROR,
58+
reason=f"{method} {endpoint} failed: {str(e)}",
59+
)
60+
)
61+
62+
return results

scim2_tester/checkers/resource_types.py

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import uuid
22

3+
from scim2_client import SCIMClientError
34
from scim2_models import Error
45
from scim2_models import ResourceType
6+
from scim2_models import Schema
57

68
from ..utils import CheckContext
79
from ..utils import CheckResult
810
from ..utils import Status
911
from ..utils import checker
12+
from ._discovery_utils import _test_discovery_endpoint_methods
1013

1114

12-
def resource_types_endpoint(context: CheckContext) -> list[CheckResult]:
15+
def _resource_types_endpoint(context: CheckContext) -> list[CheckResult]:
1316
"""Orchestrate validation of the ResourceTypes discovery endpoint.
1417
1518
Runs comprehensive tests on the ``/ResourceTypes`` endpoint including listing
@@ -28,12 +31,6 @@ def resource_types_endpoint(context: CheckContext) -> list[CheckResult]:
2831
2932
"Service providers MUST provide this endpoint."
3033
31-
.. todo::
32-
33-
- Check POST/PUT/PATCH/DELETE on the endpoint
34-
- Check that query parameters are ignored
35-
- Check that a 403 response is returned if a filter is passed
36-
- Check that the `schema` attribute exists and is available.
3734
"""
3835
resource_types_result = query_all_resource_types(context)
3936
results = [resource_types_result]
@@ -42,11 +39,89 @@ def resource_types_endpoint(context: CheckContext) -> list[CheckResult]:
4239
for resource_type in resource_types_result.data:
4340
results.append(query_resource_type_by_id(context, resource_type))
4441

42+
# Validate that all ResourceType schemas are accessible
43+
results.extend(resource_types_schema_validation(context))
44+
4545
results.append(access_invalid_resource_type(context))
4646

4747
return results
4848

4949

50+
@checker("discovery", "resource-types")
51+
def resource_types_endpoint_methods(
52+
context: CheckContext,
53+
) -> list[CheckResult]:
54+
"""Validate that unsupported HTTP methods return 405 Method Not Allowed.
55+
56+
Tests that POST, PUT, PATCH, and DELETE methods on the ``/ResourceTypes``
57+
endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported.
58+
59+
**Status:**
60+
61+
- :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status
62+
- :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status
63+
64+
.. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>`
65+
66+
"An HTTP GET to this endpoint is used to discover the types of resources
67+
available on a SCIM service provider."
68+
69+
Only GET method is specified, other methods should return appropriate errors.
70+
"""
71+
return _test_discovery_endpoint_methods(context, "/ResourceTypes")
72+
73+
74+
@checker("discovery", "resource-types")
75+
def resource_types_schema_validation(
76+
context: CheckContext,
77+
) -> list[CheckResult]:
78+
"""Validate that ResourceType schemas exist and are accessible.
79+
80+
Tests that all :class:`~scim2_models.ResourceType` objects returned by the
81+
``/ResourceTypes`` endpoint reference valid schemas that can be retrieved
82+
from the ``/Schemas`` endpoint.
83+
84+
**Status:**
85+
86+
- :attr:`~scim2_tester.Status.SUCCESS`: All ResourceType schemas are accessible
87+
- :attr:`~scim2_tester.Status.ERROR`: One or more ResourceType schemas are missing or inaccessible
88+
89+
.. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>`
90+
91+
"Each resource type defines the endpoint, the core schema URI that defines
92+
the resource, and any supported schema extensions."
93+
"""
94+
response = context.client.query(
95+
ResourceType, expected_status_codes=context.conf.expected_status_codes or [200]
96+
)
97+
98+
results = []
99+
for resource_type in response.resources:
100+
schema_id = resource_type.schema_
101+
try:
102+
schema_response = context.client.query(
103+
Schema,
104+
schema_id,
105+
expected_status_codes=context.conf.expected_status_codes or [200],
106+
)
107+
results.append(
108+
CheckResult(
109+
status=Status.SUCCESS,
110+
reason=f"ResourceType '{resource_type.name}' schema '{schema_id}' is accessible",
111+
data=schema_response,
112+
)
113+
)
114+
except SCIMClientError as e:
115+
results.append(
116+
CheckResult(
117+
status=Status.ERROR,
118+
reason=f"ResourceType '{resource_type.name}' schema '{schema_id}' is not accessible: {str(e)}",
119+
)
120+
)
121+
122+
return results
123+
124+
50125
@checker("discovery", "resource-types")
51126
def query_all_resource_types(context: CheckContext) -> CheckResult:
52127
"""Validate retrieval of all available resource types.

0 commit comments

Comments
 (0)