From 29f4bed163b55cbea2ea0ee7df9fe8ba874ca1c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Wed, 30 Jul 2025 12:29:12 +0200 Subject: [PATCH] feat: implement additional tests on the core resources --- scim2_tester/checker.py | 15 +- scim2_tester/checkers/__init__.py | 21 ++- scim2_tester/checkers/_discovery_utils.py | 61 ++++++ scim2_tester/checkers/resource.py | 4 - scim2_tester/checkers/resource_delete.py | 2 - scim2_tester/checkers/resource_types.py | 88 ++++++++- scim2_tester/checkers/schemas.py | 177 ++++++++++++++---- .../checkers/service_provider_config.py | 28 ++- tests/test_network.py | 5 +- tests/test_resource.py | 1 - tests/test_resource_types.py | 19 +- tests/test_schemas.py | 6 +- tests/test_scim2_server.py | 6 - tests/test_utils.py | 5 - 14 files changed, 342 insertions(+), 96 deletions(-) create mode 100644 scim2_tester/checkers/_discovery_utils.py diff --git a/scim2_tester/checker.py b/scim2_tester/checker.py index a4f61b5..12f3dbe 100644 --- a/scim2_tester/checker.py +++ b/scim2_tester/checker.py @@ -4,9 +4,9 @@ from scim2_tester.checkers import random_url from scim2_tester.checkers import resource_type_tests -from scim2_tester.checkers import resource_types_endpoint -from scim2_tester.checkers import schemas_endpoint from scim2_tester.checkers import service_provider_config_endpoint +from scim2_tester.checkers.resource_types import _resource_types_endpoint +from scim2_tester.checkers.schemas import _schemas_endpoint from scim2_tester.utils import CheckConfig from scim2_tester.utils import CheckContext from scim2_tester.utils import CheckResult @@ -74,25 +74,22 @@ def check_server( context = CheckContext(client, conf) results = [] - # Get the initial basic objects result_spc = service_provider_config_endpoint(context) results.append(result_spc) if result_spc.status != Status.SKIPPED and not client.service_provider_config: client.service_provider_config = result_spc.data - results_resource_types = resource_types_endpoint(context) + results_resource_types = _resource_types_endpoint(context) results.extend(results_resource_types) if not client.resource_types: - # Find first non-skipped result with data for rt_result in results_resource_types: if rt_result.status != Status.SKIPPED and rt_result.data: client.resource_types = rt_result.data break - results_schemas = schemas_endpoint(context) + results_schemas = _schemas_endpoint(context) results.extend(results_schemas) if not client.resource_models: - # Find first non-skipped result with data for schema_result in results_schemas: if schema_result.status != Status.SKIPPED and schema_result.data: client.resource_models = client.build_resource_models( @@ -107,18 +104,14 @@ def check_server( ): return results - # Miscelleaneous checks result_random = random_url(context) results.append(result_random) - # Resource checks for resource_type in client.resource_types or []: - # Filter by resource type if specified if conf.resource_types and resource_type.name not in conf.resource_types: continue resource_results = resource_type_tests(context, resource_type) - # Add resource type to each result for better tracking for result in resource_results: result.resource_type = resource_type.name results.extend(resource_results) diff --git a/scim2_tester/checkers/__init__.py b/scim2_tester/checkers/__init__.py index 948c9cc..34b96fb 100644 --- a/scim2_tester/checkers/__init__.py +++ b/scim2_tester/checkers/__init__.py @@ -20,31 +20,34 @@ from .resource_types import access_invalid_resource_type from .resource_types import query_all_resource_types from .resource_types import query_resource_type_by_id -from .resource_types import resource_types_endpoint +from .resource_types import resource_types_endpoint_methods +from .resource_types import resource_types_schema_validation from .schemas import access_invalid_schema +from .schemas import access_schema_by_id +from .schemas import core_schemas_validation from .schemas import query_all_schemas -from .schemas import query_schema_by_id -from .schemas import schemas_endpoint +from .schemas import schemas_endpoint_methods from .service_provider_config import service_provider_config_endpoint +from .service_provider_config import service_provider_config_endpoint_methods __all__ = [ - # Discovery checkers "service_provider_config_endpoint", - "resource_types_endpoint", + "service_provider_config_endpoint_methods", + "resource_types_endpoint_methods", + "resource_types_schema_validation", "query_all_resource_types", "query_resource_type_by_id", "access_invalid_resource_type", - "schemas_endpoint", + "schemas_endpoint_methods", "query_all_schemas", - "query_schema_by_id", + "access_schema_by_id", "access_invalid_schema", - # CRUD checkers + "core_schemas_validation", "object_creation", "object_query", "object_query_without_id", "object_replacement", "object_deletion", "resource_type_tests", - # Miscellaneous checkers "random_url", ] diff --git a/scim2_tester/checkers/_discovery_utils.py b/scim2_tester/checkers/_discovery_utils.py new file mode 100644 index 0000000..13989ad --- /dev/null +++ b/scim2_tester/checkers/_discovery_utils.py @@ -0,0 +1,61 @@ +"""Utility functions for discovery endpoint testing.""" + +from scim2_client import SCIMClientError + +from ..utils import CheckContext +from ..utils import CheckResult +from ..utils import Status + + +def _test_discovery_endpoint_methods( + context: CheckContext, endpoint: str +) -> list[CheckResult]: + """Test that unsupported HTTP methods return 405 Method Not Allowed. + + Tests that POST, PUT, PATCH, and DELETE methods on the specified discovery + endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status + - :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + Discovery endpoints only support GET method. Other HTTP methods + should return appropriate error responses. + """ + results = [] + methods = ["POST", "PUT", "PATCH", "DELETE"] + + for method in methods: + try: + response = context.client.client.request( + method=method, + url=endpoint, + ) + if response.status_code == 405: + results.append( + CheckResult( + status=Status.SUCCESS, + reason=f"{method} {endpoint} correctly returned 405 Method Not Allowed", + data=response, + ) + ) + else: + results.append( + CheckResult( + status=Status.ERROR, + reason=f"{method} {endpoint} returned {response.status_code} instead of 405", + data=response, + ) + ) + except SCIMClientError as e: + results.append( + CheckResult( + status=Status.ERROR, + reason=f"{method} {endpoint} failed: {str(e)}", + ) + ) + + return results diff --git a/scim2_tester/checkers/resource.py b/scim2_tester/checkers/resource.py index d8978b0..932be8f 100644 --- a/scim2_tester/checkers/resource.py +++ b/scim2_tester/checkers/resource.py @@ -43,10 +43,6 @@ def resource_type_tests( results = [] - # Each test is now completely independent and handles its own cleanup - # These functions have @checker decorators so we call them with client, conf - # The decorator will create a context and call the function appropriately - # For now, call them directly - may need adjustment based on actual function signatures results.append(object_creation(context, model)) results.append(object_query(context, model)) results.append(object_query_without_id(context, model)) diff --git a/scim2_tester/checkers/resource_delete.py b/scim2_tester/checkers/resource_delete.py index 346e4e9..4bde026 100644 --- a/scim2_tester/checkers/resource_delete.py +++ b/scim2_tester/checkers/resource_delete.py @@ -30,7 +30,6 @@ def object_deletion(context: CheckContext, model: type[Resource[Any]]) -> CheckR """ test_obj = context.resource_manager.create_and_register(model) - # Remove from resource manager since we're testing deletion explicitly if test_obj in context.resource_manager.resources: context.resource_manager.resources.remove(test_obj) @@ -48,7 +47,6 @@ def object_deletion(context: CheckContext, model: type[Resource[Any]]) -> CheckR reason=f"{model.__name__} object with id {test_obj.id} still exists after deletion", ) except Exception: - # Expected - object should not exist after deletion pass return CheckResult( diff --git a/scim2_tester/checkers/resource_types.py b/scim2_tester/checkers/resource_types.py index 290f338..0c33563 100644 --- a/scim2_tester/checkers/resource_types.py +++ b/scim2_tester/checkers/resource_types.py @@ -1,15 +1,18 @@ import uuid +from scim2_client import SCIMClientError from scim2_models import Error from scim2_models import ResourceType +from scim2_models import Schema from ..utils import CheckContext from ..utils import CheckResult from ..utils import Status from ..utils import checker +from ._discovery_utils import _test_discovery_endpoint_methods -def resource_types_endpoint(context: CheckContext) -> list[CheckResult]: +def _resource_types_endpoint(context: CheckContext) -> list[CheckResult]: """Orchestrate validation of the ResourceTypes discovery endpoint. Runs comprehensive tests on the ``/ResourceTypes`` endpoint including listing @@ -28,12 +31,6 @@ def resource_types_endpoint(context: CheckContext) -> list[CheckResult]: "Service providers MUST provide this endpoint." - .. todo:: - - - Check POST/PUT/PATCH/DELETE on the endpoint - - Check that query parameters are ignored - - Check that a 403 response is returned if a filter is passed - - Check that the `schema` attribute exists and is available. """ resource_types_result = query_all_resource_types(context) results = [resource_types_result] @@ -42,11 +39,88 @@ def resource_types_endpoint(context: CheckContext) -> list[CheckResult]: for resource_type in resource_types_result.data: results.append(query_resource_type_by_id(context, resource_type)) + results.extend(resource_types_schema_validation(context)) + results.append(access_invalid_resource_type(context)) return results +@checker("discovery", "resource-types") +def resource_types_endpoint_methods( + context: CheckContext, +) -> list[CheckResult]: + """Validate that unsupported HTTP methods return 405 Method Not Allowed. + + Tests that POST, PUT, PATCH, and DELETE methods on the ``/ResourceTypes`` + endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status + - :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + "An HTTP GET to this endpoint is used to discover the types of resources + available on a SCIM service provider." + + Only GET method is specified, other methods should return appropriate errors. + """ + return _test_discovery_endpoint_methods(context, "/ResourceTypes") + + +@checker("discovery", "resource-types") +def resource_types_schema_validation( + context: CheckContext, +) -> list[CheckResult]: + """Validate that ResourceType schemas exist and are accessible. + + Tests that all :class:`~scim2_models.ResourceType` objects returned by the + ``/ResourceTypes`` endpoint reference valid schemas that can be retrieved + from the ``/Schemas`` endpoint. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All ResourceType schemas are accessible + - :attr:`~scim2_tester.Status.ERROR`: One or more ResourceType schemas are missing or inaccessible + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + "Each resource type defines the endpoint, the core schema URI that defines + the resource, and any supported schema extensions." + """ + response = context.client.query( + ResourceType, expected_status_codes=context.conf.expected_status_codes or [200] + ) + + results = [] + for resource_type in response.resources: + schema_id = resource_type.schema_ + try: + schema_response = context.client.query( + Schema, + schema_id, + expected_status_codes=context.conf.expected_status_codes or [200], + ) + results.append( + CheckResult( + status=Status.SUCCESS, + reason=f"ResourceType '{resource_type.name}' schema '{schema_id}' is accessible", + data=schema_response, + ) + ) + except SCIMClientError as e: + results.append( + CheckResult( + status=Status.ERROR, + reason=f"ResourceType '{resource_type.name}' schema '{schema_id}' is not accessible: {str(e)}", + ) + ) + + return results + + @checker("discovery", "resource-types") def query_all_resource_types(context: CheckContext) -> CheckResult: """Validate retrieval of all available resource types. diff --git a/scim2_tester/checkers/schemas.py b/scim2_tester/checkers/schemas.py index e01aa4a..df89d4b 100644 --- a/scim2_tester/checkers/schemas.py +++ b/scim2_tester/checkers/schemas.py @@ -1,5 +1,6 @@ import uuid +from scim2_client import SCIMClientError from scim2_models import Error from scim2_models import Schema @@ -7,9 +8,10 @@ from ..utils import CheckResult from ..utils import Status from ..utils import checker +from ._discovery_utils import _test_discovery_endpoint_methods -def schemas_endpoint(context: CheckContext) -> list[CheckResult]: +def _schemas_endpoint(context: CheckContext) -> list[CheckResult]: """Orchestrate validation of the Schemas discovery endpoint. Runs comprehensive tests on the ``/Schemas`` endpoint including listing @@ -28,20 +30,12 @@ def schemas_endpoint(context: CheckContext) -> list[CheckResult]: "Service providers MUST provide this endpoint." - .. todo:: - - - Check the POST/PUT/PATCH/DELETE methods on the endpoint - - Check accessing every subschema with /Schemas/urn:ietf:params:scim:schemas:core:2.0:User - - Check that query parameters are ignored - - Check that a 403 response is returned if a filter is passed - - Check that the 'ResourceType', 'ServiceProviderConfig' and 'Schema' schemas are provided. """ schemas_result = query_all_schemas(context) results = [schemas_result] if schemas_result.status == Status.SUCCESS: - for resource_type in schemas_result.data: - results.append(query_schema_by_id(context, resource_type)) + results.extend(access_schema_by_id(context)) results.append(access_invalid_schema(context)) @@ -76,35 +70,6 @@ def query_all_schemas(context: CheckContext) -> CheckResult: ) -@checker("discovery", "schemas") -def query_schema_by_id(context: CheckContext, schema: Schema) -> CheckResult: - """Validate individual schema retrieval by ID. - - Tests that specific schemas can be retrieved using GET requests to - ``/Schemas/{id}`` with their complete attribute definitions and metadata. - - **Status:** - - - :attr:`~scim2_tester.Status.SUCCESS`: :class:`~scim2_models.Schema` retrieved successfully with valid data - - :attr:`~scim2_tester.Status.ERROR`: Failed to retrieve or received invalid response - - .. pull-quote:: :rfc:`RFC 7644 Section 7 - Schema Definition <7644#section-7>` - - "Each schema specifies the name of the resource, the resource's base URI, - and any attributes (including sub-attributes) of the resource." - """ - response = context.client.query( - Schema, - schema.id, - expected_status_codes=context.conf.expected_status_codes or [200], - ) - if isinstance(response, Error): - return CheckResult(status=Status.ERROR, reason=response.detail, data=response) - - reason = f"Successfully accessed the /Schemas/{schema.id} endpoint." - return CheckResult(status=Status.SUCCESS, reason=reason, data=response) - - @checker("discovery", "schemas") def access_invalid_schema(context: CheckContext) -> CheckResult: """Validate error handling for non-existent schema IDs. @@ -149,3 +114,137 @@ def access_invalid_schema(context: CheckContext) -> CheckResult: reason=f"/Schemas/{probably_invalid_id} invalid URL correctly returned a 404 error", data=response, ) + + +@checker("discovery", "schemas") +def schemas_endpoint_methods( + context: CheckContext, +) -> list[CheckResult]: + """Validate that unsupported HTTP methods return 405 Method Not Allowed. + + Tests that POST, PUT, PATCH, and DELETE methods on the ``/Schemas`` + endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status + - :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + "An HTTP GET to this endpoint is used to retrieve information about + resource schemas supported by a SCIM service provider." + + Only GET method is specified, other methods should return appropriate errors. + """ + return _test_discovery_endpoint_methods(context, "/Schemas") + + +@checker("discovery", "schemas") +def access_schema_by_id( + context: CheckContext, +) -> list[CheckResult]: + """Validate individual schema retrieval by ID. + + Tests that all schemas can be retrieved using GET requests to + ``/Schemas/{id}`` with their complete attribute definitions and metadata. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All schemas retrieved successfully with valid data + - :attr:`~scim2_tester.Status.ERROR`: One or more schemas failed to retrieve + + .. pull-quote:: :rfc:`RFC 7644 Section 7 - Schema Definition <7644#section-7>` + + "Each schema specifies the name of the resource, the resource's base URI, + and any attributes (including sub-attributes) of the resource." + """ + schemas_response = context.client.query( + Schema, expected_status_codes=context.conf.expected_status_codes or [200] + ) + + results = [] + for schema in schemas_response.resources: + if schema.id: + try: + response = context.client.query( + Schema, + schema.id, + expected_status_codes=context.conf.expected_status_codes or [200], + ) + results.append( + CheckResult( + status=Status.SUCCESS, + reason=f"Successfully accessed schema: {schema.id}", + data=response, + ) + ) + except SCIMClientError as e: + results.append( + CheckResult( + status=Status.ERROR, + reason=f"Failed to access schema {schema.id}: {str(e)}", + ) + ) + + if not results: + results.append( + CheckResult( + status=Status.SUCCESS, + reason="No schemas with IDs found to test", + ) + ) + + return results + + +@checker("discovery", "schemas") +def core_schemas_validation( + context: CheckContext, +) -> CheckResult: + """Validate that mandatory core schemas are provided. + + Tests that the ``/Schemas`` endpoint provides the three mandatory core schemas: + ResourceType, ServiceProviderConfig, and Schema schemas themselves. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All mandatory core schemas are present + - :attr:`~scim2_tester.Status.ERROR`: One or more mandatory schemas are missing + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + "Service providers MUST provide this endpoint." + + The core schemas for ResourceType, ServiceProviderConfig, and Schema + objects are fundamental to SCIM operation and should always be available. + """ + response = context.client.query( + Schema, expected_status_codes=context.conf.expected_status_codes or [200] + ) + + required_schemas = { + "ResourceType": False, + "ServiceProviderConfig": False, + "Schema": False, + } + + for schema in response.resources: + schema_name = getattr(schema, "name", "") + if schema_name in required_schemas: + required_schemas[schema_name] = True + + missing_schemas = [name for name, found in required_schemas.items() if not found] + + if missing_schemas: + return CheckResult( + status=Status.ERROR, + reason=f"Missing mandatory core schemas: {', '.join(missing_schemas)}", + data=response, + ) + + return CheckResult( + status=Status.SUCCESS, + reason="All mandatory core schemas (ResourceType, ServiceProviderConfig, Schema) are present", + data=response, + ) diff --git a/scim2_tester/checkers/service_provider_config.py b/scim2_tester/checkers/service_provider_config.py index e09de3e..3e21eff 100644 --- a/scim2_tester/checkers/service_provider_config.py +++ b/scim2_tester/checkers/service_provider_config.py @@ -4,6 +4,7 @@ from ..utils import CheckResult from ..utils import Status from ..utils import checker +from ._discovery_utils import _test_discovery_endpoint_methods @checker("discovery", "service-provider-config") @@ -28,12 +29,33 @@ def service_provider_config_endpoint( "Service providers MUST provide this endpoint." - .. todo:: - - Check that POST/PUT/PATCH/DELETE methods on the endpoint return appropriate errors """ response = context.client.query( ServiceProviderConfig, expected_status_codes=context.conf.expected_status_codes or [200], ) return CheckResult(status=Status.SUCCESS, data=response) + + +@checker("discovery", "service-provider-config") +def service_provider_config_endpoint_methods( + context: CheckContext, +) -> list[CheckResult]: + """Validate that unsupported HTTP methods return 405 Method Not Allowed. + + Tests that POST, PUT, PATCH, and DELETE methods on the ``/ServiceProviderConfig`` + endpoint correctly return HTTP 405 Method Not Allowed status, as only GET is supported. + + **Status:** + + - :attr:`~scim2_tester.Status.SUCCESS`: All unsupported methods return 405 status + - :attr:`~scim2_tester.Status.ERROR`: One or more methods return unexpected status + + .. pull-quote:: :rfc:`RFC 7644 Section 4 - Discovery <7644#section-4>` + + "An HTTP GET to this endpoint will return a JSON structure that describes + the SCIM specification features available on a service provider." + + Only GET method is specified, other methods should return appropriate errors. + """ + return _test_discovery_endpoint_methods(context, "/ServiceProviderConfig") diff --git a/tests/test_network.py b/tests/test_network.py index c4a0647..8c6564e 100644 --- a/tests/test_network.py +++ b/tests/test_network.py @@ -8,7 +8,7 @@ from scim2_models import User from scim2_tester.checker import check_server -from scim2_tester.checkers import schemas_endpoint +from scim2_tester.checkers.schemas import _schemas_endpoint from scim2_tester.utils import CheckConfig from scim2_tester.utils import CheckContext from scim2_tester.utils import CheckResult @@ -39,7 +39,7 @@ def test_bad_authentication(httpserver): scim = SyncSCIMClient(client, resource_models=(User, Group)) conf = CheckConfig(expected_status_codes=[200, 401]) context = CheckContext(scim, conf) - results = schemas_endpoint(context) + results = _schemas_endpoint(context) assert results[0].status == Status.ERROR assert ( @@ -78,7 +78,6 @@ def test_bad_content_type(httpserver): conf = CheckConfig() context = CheckContext(scim, conf) - # Simple test function for network content types def simple_query_test(context, obj): """Direct query test without ResourceManager for network testing.""" try: diff --git a/tests/test_resource.py b/tests/test_resource.py index 7db8cd3..9d42675 100644 --- a/tests/test_resource.py +++ b/tests/test_resource.py @@ -50,7 +50,6 @@ class Type(str, Enum): def test_random_values(): """Check that 'fill_with_random_values' produce valid objects.""" - # Create a mock config and resource manager for testing class MockClient: def create(self, obj): return obj diff --git a/tests/test_resource_types.py b/tests/test_resource_types.py index 7fffc5e..9f8525e 100644 --- a/tests/test_resource_types.py +++ b/tests/test_resource_types.py @@ -4,8 +4,9 @@ from scim2_models import Error from scim2_models import ListResponse from scim2_models import ResourceType +from scim2_models import Schema -from scim2_tester.checkers import resource_types_endpoint +from scim2_tester.checkers.resource_types import _resource_types_endpoint from scim2_tester.utils import Status @@ -27,13 +28,25 @@ def test_resource_types_endpoint(httpserver, check_config): status=200, content_type="application/scim+json", ) + mock_schema = Schema( + id=resource_type.schema_, + name=resource_type.name, + description=f"Schema for {resource_type.name}", + ) + httpserver.expect_request( + re.compile(rf"^/Schemas/{re.escape(resource_type.schema_)}$") + ).respond_with_json( + mock_schema.model_dump(scim_ctx=Context.RESOURCE_QUERY_RESPONSE), + status=200, + content_type="application/scim+json", + ) httpserver.expect_request(re.compile(r"^/ResourceTypes/.*$")).respond_with_json( Error(status=404, detail="ResourceType Not Found").model_dump(), status=404, content_type="application/scim+json", ) - results = resource_types_endpoint(check_config) + results = _resource_types_endpoint(check_config) assert all(result.status == Status.SUCCESS for result in results) @@ -48,6 +61,6 @@ def test_resource_missing_query_endpoint(httpserver, check_config): status=200, content_type="application/scim+json", ) - results = resource_types_endpoint(check_config) + results = _resource_types_endpoint(check_config) assert all(result.status == Status.ERROR for result in results[1:]) diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 035a6d2..837e477 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -5,7 +5,7 @@ from scim2_models import ListResponse from scim2_models import Schema -from scim2_tester.checkers import schemas_endpoint +from scim2_tester.checkers.schemas import _schemas_endpoint from scim2_tester.utils import Status @@ -34,7 +34,7 @@ def test_shemas_endpoint(httpserver, check_config): content_type="application/scim+json", ) - results = schemas_endpoint(check_config) + results = _schemas_endpoint(check_config) assert all(result.status == Status.SUCCESS for result in results) @@ -50,6 +50,6 @@ def test_missing_query_endpoint(httpserver, check_config): status=200, content_type="application/scim+json", ) - results = schemas_endpoint(check_config) + results = _schemas_endpoint(check_config) assert all(result.status == Status.ERROR for result in results[1:]) diff --git a/tests/test_scim2_server.py b/tests/test_scim2_server.py index db80205..b0aee9a 100644 --- a/tests/test_scim2_server.py +++ b/tests/test_scim2_server.py @@ -32,7 +32,6 @@ def test_discovered_scim2_server(scim2_server): client.discover() results = check_server(client, raise_exceptions=False) - # Verify all tests executed successfully (no skipped) executed_results = [r for r in results if r.status != Status.SKIPPED] assert len(executed_results) > 0 assert all(r.status in (Status.SUCCESS, Status.ERROR) for r in executed_results) @@ -43,7 +42,6 @@ def test_undiscovered_scim2_server(scim2_server): client = TestSCIMClient(Client(scim2_server)) results = check_server(client, raise_exceptions=False) - # Verify all tests executed successfully (no skipped) executed_results = [r for r in results if r.status != Status.SKIPPED] assert len(executed_results) > 0 assert all(r.status in (Status.SUCCESS, Status.ERROR) for r in executed_results) @@ -73,7 +71,6 @@ def test_filtering_functionality(scim2_server): all_results = check_server(client, raise_exceptions=False) all_executed = [r for r in all_results if r.status != Status.SKIPPED] - # Test discovery only discovery_results = check_server( client, raise_exceptions=False, include_tags={"discovery"} ) @@ -91,7 +88,6 @@ def test_filtering_functionality(scim2_server): "Expected fewer results when filtering" ) - # Test misc only misc_results = check_server(client, raise_exceptions=False, include_tags={"misc"}) misc_executed = [r for r in misc_results if r.status != Status.SKIPPED] @@ -125,11 +121,9 @@ def test_tag_discovery_utility(scim2_server): f"Expected at least 8 core tags, got {len(discovered_core)}: {discovered_core}" ) - # Test with actual server - only test discoverable function-level tags client = TestSCIMClient(Client(scim2_server)) client.discover() - # Test function-level tags function_level_tags = { "discovery", "service-provider-config", diff --git a/tests/test_utils.py b/tests/test_utils.py index 5ae5a7f..b54a3f5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -20,7 +20,6 @@ def check_function(context: CheckContext) -> CheckResult: assert hasattr(check_function, "tags") assert check_function.tags == {"tag1", "tag2"} - # Test that result gets tags conf = CheckConfig(raise_exceptions=False) context = CheckContext(client=None, conf=conf) result = check_function(context) @@ -41,7 +40,6 @@ def check_function(context: CheckContext) -> CheckResult: assert hasattr(check_function, "tags") assert check_function.tags == set() - # Test that result gets empty tags conf = CheckConfig(raise_exceptions=False) context = CheckContext(client=None, conf=conf) result = check_function(context) @@ -243,7 +241,6 @@ def complex_check(context): assert "Multiple check failures" in str(exception_group) assert len(exception_group.exceptions) == 3 # Three errors - # Verify each error is a SCIMTesterError with the right message error_messages = [str(e) for e in exception_group.exceptions] expected_messages = [ "Authentication failed", @@ -289,13 +286,11 @@ def test_func(context): return CheckResult(status=Status.SUCCESS) - # Test include tags matching conf_include = CheckConfig(include_tags={"crud"}) context_include = CheckContext(client=None, conf=conf_include) result = test_func(context_include) # Call with decorator signature assert result.status.name == "SUCCESS" - # Test exclude tags matching conf_exclude = CheckConfig(exclude_tags={"crud"}) context_exclude = CheckContext(client=None, conf=conf_exclude) result = test_func(context_exclude) # Call with decorator signature