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 as Write a storage explains, 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 runs each filter and each sort of a list, and compares the answer of the
storage with the rules of SCIM. It uses the User and Group resource types of RFC 7643.
Run the suite#
Install the
testingextra, which installs pytest:$ pip install "scim2-server[testing]"In a test module, subclass
ScimStorageContract, and give it astoragefixture that returns a new, empty storage. Theproviderfixture of the suite gives the description of the service, that the storage needs. For anAsyncScimStorage, subclassAsyncScimStorageContractinstead, and name the fixtureasync_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.
Run pytest. Every test of the suite runs against the storage:
$ pytest ........................................................................ [ 66%] .................................... [100%] 108 passed in 6.09s
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 [46] scim2_server/testing.py:216: The service does not support filtering
SKIPPED [19] scim2_server/testing.py:216: The service does not support sorting
SKIPPED [10] scim2_server/testing.py:216: The service does not support cursor pagination
======================= 33 passed, 75 skipped in 6.57s =========================
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:216: The service does not support searching at the root
SKIPPED [10] scim2_server/testing.py:216: The service does not support cursor pagination
======================= 96 passed, 12 skipped in 6.79s =========================
A storage refuses a filter it cannot translate with InvalidFilterException,
and a sort with InvalidPathException. The suite skips the filters and the
sorts the storage refuses, and checks the others:
$ pytest -rs
SKIPPED [11] scim2_server/testing.py:700: The storage refuses the search: Cannot filter on 'title'
SKIPPED [2] scim2_server/testing.py:700: The storage refuses the search: Cannot sort on 'title'
The filters and the sorts search users with the attributes of the User resource type and of
its enterprise extension. For a storage that does not store some of them, override
search_users(), and return the users without
these attributes. The suite skips the filters and the sorts on the attributes the models of
the provider fixture lack.