Check a storage#

Use this guide to check that a storage follows the rules of ScimStorage, with the test suite scim2-server provides. It assumes a storage written with Write a storage, and tests run with pytest.

The suite checks what the method signatures do not tell: the copies, the 404 and 412 errors, the dates and versions, the uniqueness of userName, and the filters, sorting and paging of the searches. It uses the User and Group resource types of RFC 7643.

Run the suite#

  1. Install the testing extra, which installs pytest:

    $ pip install "scim2-server[testing]"
    
  2. In a test module, subclass ScimStorageContract, and give it a storage fixture that returns a new, empty storage. The provider fixture of the suite gives the description of the service, that the storage needs. For an AsyncScimStorage, subclass AsyncScimStorageContract instead, and name the fixture async_storage:

    import sqlite3
    
    import pytest
    from scim2_server.testing import ScimStorageContract
    
    from myapp.scim import SQLiteStorage
    
    
    class TestSQLiteStorage(ScimStorageContract):
        @pytest.fixture
        def storage(self, provider):
            connection = sqlite3.connect(":memory:")
            yield SQLiteStorage(connection, provider)
            connection.close()
    
    import asyncio
    
    import pytest
    from scim2_server.testing import AsyncScimStorageContract
    
    from myapp.scim import AsyncSQLiteStorage
    
    
    class TestAsyncSQLiteStorage(AsyncScimStorageContract):
        @pytest.fixture
        def async_storage(self, provider):
            storage = AsyncSQLiteStorage(":memory:", provider)
            yield storage
            asyncio.run(storage.close())
    

    The asynchronous suite runs the same tests. Each test runs the coroutines of the storage on its own event loop.

  3. Run pytest. Every test of the suite runs against the storage:

    $ pytest
    ..............................                                           [100%]
    30 passed in 0.83s
    

Skip what the storage does not support#

The suite skips the tests of a feature that the service does not announce. pytest lists these tests as skipped, with the feature they need.

Describe the service as the server announces it. For a storage that cannot filter or sort, override the provider fixture. In its ServiceProviderConfig, set supported to False for filter or sort:

import sqlite3

import pytest
from myapp.scim import SQLiteStorage

from scim2_server.testing import ScimStorageContract
from scim2_server.utils import load_default_provider


class TestStorageWithoutFilterNorSort(ScimStorageContract):
    @pytest.fixture
    def storage(self, provider):
        connection = sqlite3.connect(":memory:")
        yield SQLiteStorage(connection, provider)
        connection.close()

    @pytest.fixture
    def provider(self):
        provider = load_default_provider()
        provider.config.filter.supported = False
        provider.config.sort.supported = False
        return provider
$ pytest -rs
SKIPPED [2] scim2_server/testing.py:101: The service does not support filtering
SKIPPED [1] scim2_server/testing.py:101: The service does not support sorting
======================== 27 passed, 3 skipped in 1.03s =========================

For a storage that cannot search several resource types at once, set supports_root_search to False:

import sqlite3

import pytest
from myapp.scim import SQLiteStorage

from scim2_server.testing import ScimStorageContract


class TestStorageWithoutRootSearch(ScimStorageContract):
    supports_root_search = False

    @pytest.fixture
    def storage(self, provider):
        connection = sqlite3.connect(":memory:")
        yield SQLiteStorage(connection, provider)
        connection.close()
$ pytest -rs
SKIPPED [2] scim2_server/testing.py:101: The service does not support searching at the root
======================== 28 passed, 2 skipped in 0.99s =========================