Skip to content

Commit b08e48e

Browse files
committed
refactor: move checkers in a dedicated directory and document them
1 parent 910053d commit b08e48e

16 files changed

Lines changed: 186 additions & 124 deletions

doc/reference.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
Reference
22
=========
33

4+
Checkers
5+
--------
6+
7+
.. automodule:: scim2_tester.checkers
8+
:members:
9+
10+
Public API
11+
----------
12+
413
.. automodule:: scim2_tester
514
:members:

scim2_tester/checker.py

Lines changed: 10 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,16 @@
11
import argparse
2-
import uuid
3-
from typing import Any
42

53
from scim2_client.engines.httpx import SyncSCIMClient
6-
from scim2_models import Error
74

8-
from scim2_tester.resource import check_resource_type
9-
from scim2_tester.resource_types import check_resource_types_endpoint
10-
from scim2_tester.schemas import check_schemas_endpoint
11-
from scim2_tester.service_provider_config import check_service_provider_config_endpoint
5+
from scim2_tester.checkers import random_url
6+
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
9+
from scim2_tester.checkers import service_provider_config_endpoint
1210
from scim2_tester.utils import CheckConfig
1311
from scim2_tester.utils import CheckContext
1412
from scim2_tester.utils import CheckResult
1513
from scim2_tester.utils import Status
16-
from scim2_tester.utils import checker
17-
18-
19-
@checker("misc")
20-
def check_random_url(context: CheckContext) -> CheckResult:
21-
"""Check that a request to a random URL returns a 404 Error object."""
22-
probably_invalid_url = f"/{str(uuid.uuid4())}"
23-
response: Any = context.client.query(
24-
url=probably_invalid_url, raise_scim_errors=False
25-
)
26-
27-
if not isinstance(response, Error):
28-
return CheckResult(
29-
status=Status.ERROR,
30-
reason=f"{probably_invalid_url} did not return an Error object",
31-
data=response,
32-
)
33-
34-
if response.status != 404:
35-
return CheckResult(
36-
status=Status.ERROR,
37-
reason=f"{probably_invalid_url} did return an object, but the status code is {response.status}",
38-
data=response,
39-
)
40-
41-
return CheckResult(
42-
status=Status.SUCCESS,
43-
reason=f"{probably_invalid_url} correctly returned a 404 error",
44-
data=response,
45-
)
4614

4715

4816
def check_server(
@@ -107,12 +75,12 @@ def check_server(
10775
results = []
10876

10977
# Get the initial basic objects
110-
result_spc = check_service_provider_config_endpoint(context)
78+
result_spc = service_provider_config_endpoint(context)
11179
results.append(result_spc)
11280
if result_spc.status != Status.SKIPPED and not client.service_provider_config:
11381
client.service_provider_config = result_spc.data
11482

115-
results_resource_types = check_resource_types_endpoint(context)
83+
results_resource_types = resource_types_endpoint(context)
11684
results.extend(results_resource_types)
11785
if not client.resource_types:
11886
# Find first non-skipped result with data
@@ -121,7 +89,7 @@ def check_server(
12189
client.resource_types = rt_result.data
12290
break
12391

124-
results_schemas = check_schemas_endpoint(context)
92+
results_schemas = schemas_endpoint(context)
12593
results.extend(results_schemas)
12694
if not client.resource_models:
12795
# Find first non-skipped result with data
@@ -140,7 +108,7 @@ def check_server(
140108
return results
141109

142110
# Miscelleaneous checks
143-
result_random = check_random_url(context)
111+
result_random = random_url(context)
144112
results.append(result_random)
145113

146114
# Resource checks
@@ -149,7 +117,7 @@ def check_server(
149117
if conf.resource_types and resource_type.name not in conf.resource_types:
150118
continue
151119

152-
resource_results = check_resource_type(context, resource_type)
120+
resource_results = resource_type_tests(context, resource_type)
153121
# Add resource type to each result for better tracking
154122
for result in resource_results:
155123
result.resource_type = resource_type.name

scim2_tester/checkers/__init__.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""SCIM server compliance checkers.
2+
3+
This module contains all the individual checkers for validating SCIM server implementations.
4+
Each checker is decorated with tags that allow selective test execution.
5+
6+
Available checker categories:
7+
8+
- discovery: ServiceProviderConfig, ResourceTypes, Schemas endpoints
9+
- crud: Create, Read, Update, Delete operations
10+
- misc: Random URL access tests
11+
"""
12+
13+
from .misc import random_url
14+
from .resource import resource_type_tests
15+
from .resource_delete import object_deletion
16+
from .resource_get import model_from_resource_type
17+
from .resource_get import object_query
18+
from .resource_get import object_query_without_id
19+
from .resource_post import object_creation
20+
from .resource_put import object_replacement
21+
from .resource_types import access_invalid_resource_type
22+
from .resource_types import query_all_resource_types
23+
from .resource_types import query_resource_type_by_id
24+
from .resource_types import resource_types_endpoint
25+
from .schemas import access_invalid_schema
26+
from .schemas import query_all_schemas
27+
from .schemas import query_schema_by_id
28+
from .schemas import schemas_endpoint
29+
from .service_provider_config import service_provider_config_endpoint
30+
31+
__all__ = [
32+
# Discovery checkers
33+
"service_provider_config_endpoint",
34+
"resource_types_endpoint",
35+
"query_all_resource_types",
36+
"query_resource_type_by_id",
37+
"access_invalid_resource_type",
38+
"schemas_endpoint",
39+
"query_all_schemas",
40+
"query_schema_by_id",
41+
"access_invalid_schema",
42+
# CRUD checkers
43+
"object_creation",
44+
"object_query",
45+
"object_query_without_id",
46+
"object_replacement",
47+
"object_deletion",
48+
"resource_type_tests",
49+
# Miscellaneous checkers
50+
"random_url",
51+
# Utilities
52+
"model_from_resource_type",
53+
]

scim2_tester/checkers/misc.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import uuid
2+
from typing import Any
3+
4+
from scim2_models import Error
5+
6+
from ..utils import CheckContext
7+
from ..utils import CheckResult
8+
from ..utils import Status
9+
from ..utils import checker
10+
11+
12+
@checker("misc")
13+
def random_url(context: CheckContext) -> CheckResult:
14+
"""Check that a request to a random URL returns a 404 Error object."""
15+
probably_invalid_url = f"/{str(uuid.uuid4())}"
16+
response: Any = context.client.query(
17+
url=probably_invalid_url, raise_scim_errors=False
18+
)
19+
20+
if not isinstance(response, Error):
21+
return CheckResult(
22+
status=Status.ERROR,
23+
reason=f"{probably_invalid_url} did not return an Error object",
24+
data=response,
25+
)
26+
27+
if response.status != 404:
28+
return CheckResult(
29+
status=Status.ERROR,
30+
reason=f"{probably_invalid_url} did return an object, but the status code is {response.status}",
31+
data=response,
32+
)
33+
34+
return CheckResult(
35+
status=Status.SUCCESS,
36+
reason=f"{probably_invalid_url} correctly returned a 404 error",
37+
data=response,
38+
)
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
from scim2_models import ResourceType
22

3-
from scim2_tester.resource_delete import check_object_deletion
4-
from scim2_tester.resource_get import check_object_query
5-
from scim2_tester.resource_get import check_object_query_without_id
6-
from scim2_tester.resource_get import model_from_resource_type
7-
from scim2_tester.resource_post import check_object_creation
8-
from scim2_tester.resource_put import check_object_replacement
9-
from scim2_tester.utils import CheckContext
10-
from scim2_tester.utils import CheckResult
11-
from scim2_tester.utils import Status
3+
from ..utils import CheckContext
4+
from ..utils import CheckResult
5+
from ..utils import Status
6+
from .resource_delete import object_deletion
7+
from .resource_get import model_from_resource_type
8+
from .resource_get import object_query
9+
from .resource_get import object_query_without_id
10+
from .resource_post import object_creation
11+
from .resource_put import object_replacement
1212

1313

14-
def check_resource_type(
14+
def resource_type_tests(
1515
context: CheckContext,
1616
resource_type: ResourceType,
1717
) -> list[CheckResult]:
@@ -36,10 +36,10 @@ def check_resource_type(
3636
# These functions have @checker decorators so we call them with client, conf
3737
# The decorator will create a context and call the function appropriately
3838
# For now, call them directly - may need adjustment based on actual function signatures
39-
results.append(check_object_creation(context, model))
40-
results.append(check_object_query(context, model))
41-
results.append(check_object_query_without_id(context, model))
42-
results.append(check_object_replacement(context, model))
43-
results.append(check_object_deletion(context, model))
39+
results.append(object_creation(context, model))
40+
results.append(object_query(context, model))
41+
results.append(object_query_without_id(context, model))
42+
results.append(object_replacement(context, model))
43+
results.append(object_deletion(context, model))
4444

4545
return results
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22

33
from scim2_models import Resource
44

5-
from scim2_tester.utils import CheckContext
6-
from scim2_tester.utils import CheckResult
7-
from scim2_tester.utils import Status
8-
from scim2_tester.utils import checker
5+
from ..utils import CheckContext
6+
from ..utils import CheckResult
7+
from ..utils import Status
8+
from ..utils import checker
99

1010

1111
@checker("crud:delete")
12-
def check_object_deletion(
13-
context: CheckContext, model: type[Resource[Any]]
14-
) -> CheckResult:
12+
def object_deletion(context: CheckContext, model: type[Resource[Any]]) -> CheckResult:
1513
"""Test object deletion with automatic cleanup.
1614
1715
Creates a test object specifically for deletion testing, performs the
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from scim2_models import Resource
44
from scim2_models import ResourceType
55

6-
from scim2_tester.utils import CheckContext
7-
from scim2_tester.utils import CheckResult
8-
from scim2_tester.utils import Status
9-
from scim2_tester.utils import checker
6+
from ..utils import CheckContext
7+
from ..utils import CheckResult
8+
from ..utils import Status
9+
from ..utils import checker
1010

1111

1212
def model_from_resource_type(
@@ -29,9 +29,7 @@ def model_from_resource_type(
2929

3030

3131
@checker("crud:read")
32-
def check_object_query(
33-
context: CheckContext, model: type[Resource[Any]]
34-
) -> CheckResult:
32+
def object_query(context: CheckContext, model: type[Resource[Any]]) -> CheckResult:
3533
"""Test object query by ID with automatic cleanup.
3634
3735
Creates a temporary test object, queries it by ID to validate the
@@ -57,7 +55,7 @@ def check_object_query(
5755

5856

5957
@checker("crud:read")
60-
def check_object_query_without_id(
58+
def object_query_without_id(
6159
context: CheckContext, model: type[Resource[Any]]
6260
) -> CheckResult:
6361
"""Test object listing without ID with automatic cleanup.
Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22

33
from scim2_models import Resource
44

5-
from scim2_tester.utils import CheckContext
6-
from scim2_tester.utils import CheckResult
7-
from scim2_tester.utils import Status
8-
from scim2_tester.utils import checker
5+
from ..utils import CheckContext
6+
from ..utils import CheckResult
7+
from ..utils import Status
8+
from ..utils import checker
99

1010

1111
@checker("crud:create")
12-
def check_object_creation(
13-
context: CheckContext, model: type[Resource[Any]]
14-
) -> CheckResult:
12+
def object_creation(context: CheckContext, model: type[Resource[Any]]) -> CheckResult:
1513
"""Test object creation with automatic cleanup.
1614
1715
Creates a test object of the specified model type, validates the creation
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
from scim2_models import Mutability
44
from scim2_models import Resource
55

6-
from scim2_tester.filling import fill_with_random_values
7-
from scim2_tester.utils import CheckContext
8-
from scim2_tester.utils import CheckResult
9-
from scim2_tester.utils import Status
10-
from scim2_tester.utils import checker
6+
from ..filling import fill_with_random_values
7+
from ..utils import CheckContext
8+
from ..utils import CheckResult
9+
from ..utils import Status
10+
from ..utils import checker
1111

1212

1313
@checker("crud:update")
14-
def check_object_replacement(
14+
def object_replacement(
1515
context: CheckContext, model: type[Resource[Any]]
1616
) -> CheckResult:
1717
"""Test object replacement (PUT) with automatic cleanup.

0 commit comments

Comments
 (0)