Skip to content

Commit 6562a06

Browse files
committed
feat: server compliance test
1 parent af6f8f8 commit 6562a06

9 files changed

Lines changed: 159 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# scim2-cli
22

3-
An utility command line to help you perform requests against a SCIM server, while validating input and response payloads.
3+
An utility command line to help you perform requests against a SCIM server, while validating input and response payloads. It also uses [scim2-tester](https://scim2-tester.readthedocs.io) to perform a [SCIM server compliance test](https://scim2-cli.readthedocs.io/en/latest/reference.html#scim-url-test).
44

55
## What's SCIM anyway?
66

doc/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Changelog
44
Added
55
^^^^^
66
- Add support for passing custom headers to requests.
7+
- Server compliance test.
78

89
[0.1.1] - 2024-06-02
910
--------------------

doc/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
intersphinx_mapping = {
4242
"python": ("https://docs.python.org/3", None),
43+
"scim2_tester": ("https://scim2-tester.readthedocs.io/en/latest/", None),
4344
}
4445

4546
# -- Options for HTML output ----------------------------------------------

poetry.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ classifiers = [
2828
python = "^3.10"
2929
click = "^8.1.7"
3030
scim2-client = "^0.1.6"
31+
scim2-tester = "^0.1.2"
3132
sphinx-click-rst-to-ansi-formatter = "^0.1.0"
3233

3334
[tool.poetry.group.doc]

scim2_cli/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .query import query_cli
1313
from .replace import replace_cli
1414
from .search import search_cli
15+
from .test import test_cli
1516
from .utils import DOC_URL
1617

1718

@@ -44,3 +45,4 @@ def cli(ctx, url):
4445
cli.add_command(replace_cli)
4546
cli.add_command(delete_cli)
4647
cli.add_command(search_cli)
48+
cli.add_command(test_cli)

scim2_cli/test.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import click
2+
from scim2_tester import Status
3+
from scim2_tester import check_server
4+
from sphinx_click.rst_to_ansi_formatter import make_rst_to_ansi_formatter
5+
6+
from .utils import DOC_URL
7+
from .utils import Color
8+
from .utils import split_headers
9+
10+
11+
@click.command(cls=make_rst_to_ansi_formatter(DOC_URL), name="test")
12+
@click.pass_context
13+
@click.option(
14+
"-h", "--headers", multiple=True, help="Header to pass in the HTTP requests."
15+
)
16+
@click.option("-v", "--verbose", is_flag=True, help="Enables verbose mode")
17+
def test_cli(ctx, headers, verbose):
18+
"""Perform a server SCIM compliance check using
19+
:doc:scim2-tester:`scim2-tester <index>`.
20+
21+
.. code-block:: bash
22+
23+
scim https://scim.example test
24+
"""
25+
26+
client = ctx.obj["client"]
27+
client.client.headers.update(split_headers(headers))
28+
results = check_server(client)
29+
click.echo(f"Performing a SCIM compliance check on {client.client.base_url} ...")
30+
for result in results:
31+
if result.status == Status.SUCCESS:
32+
status = click.style(result.status.name, fg=Color.green)
33+
else:
34+
status = click.style(result.status.name, fg=Color.red)
35+
click.echo(f"{status} {result.title}")
36+
37+
if result.reason:
38+
click.echo(f" {result.reason}")
39+
if verbose and result.data:
40+
click.echo(f" {result.data}")

scim2_cli/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
import json
2+
from enum import Enum
23

34
DOC_URL = "https://scim2-cli.readthedocs.io/"
45
INDENTATION_SIZE = 4
56

67

8+
class Color(str, Enum):
9+
black = "black"
10+
red = "red"
11+
green = "green"
12+
yellow = "yellow"
13+
blue = "blue"
14+
magenta = "magenta"
15+
cyan = "cyan"
16+
white = "white"
17+
bright_black = "bright_black"
18+
bright_red = "bright_red"
19+
bright_green = "bright_green"
20+
bright_yellow = "bright_yellow"
21+
bright_blue = "bright_blue"
22+
bright_magenta = "bright_magenta"
23+
bright_cyan = "bright_cyan"
24+
bright_white = "bright_white"
25+
26+
727
def formatted_payload(obj, indent):
828
indent = INDENTATION_SIZE if indent else False
929
return json.dumps(obj, indent=indent)

tests/test_test.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from unittest.mock import patch
2+
3+
from scim2_tester import CheckResult
4+
from scim2_tester import Status
5+
6+
from scim2_cli import cli
7+
8+
9+
def test_nominal(runner, httpserver):
10+
"""Test SCIM compliance test."""
11+
12+
results = [
13+
CheckResult(
14+
status=Status.SUCCESS,
15+
title="test1",
16+
description="description1",
17+
reason="reason1",
18+
data="data1",
19+
),
20+
CheckResult(
21+
status=Status.ERROR,
22+
title="test2",
23+
description="description2",
24+
data="data2",
25+
),
26+
]
27+
with patch("scim2_cli.test.check_server", side_effect=[results]):
28+
result = runner.invoke(
29+
cli,
30+
[httpserver.url_for("/"), "test"],
31+
catch_exceptions=False,
32+
)
33+
assert result.exit_code == 0, result.stdout
34+
35+
expected_output = f"""Performing a SCIM compliance check on http://localhost:{httpserver.port}/ ...
36+
SUCCESS test1
37+
reason1
38+
ERROR test2
39+
"""
40+
assert result.output == expected_output
41+
42+
43+
def test_verbose(runner, httpserver):
44+
"""Test SCIM compliance test."""
45+
46+
results = [
47+
CheckResult(
48+
status=Status.SUCCESS,
49+
title="test1",
50+
description="description1",
51+
reason="reason1",
52+
data="data1",
53+
),
54+
CheckResult(
55+
status=Status.ERROR,
56+
title="test2",
57+
description="description2",
58+
reason="reason2",
59+
data="data2",
60+
),
61+
]
62+
with patch("scim2_cli.test.check_server", side_effect=[results]):
63+
result = runner.invoke(
64+
cli,
65+
[httpserver.url_for("/"), "test", "--verbose"],
66+
catch_exceptions=False,
67+
)
68+
assert result.exit_code == 0, result.stdout
69+
70+
expected_output = f"""Performing a SCIM compliance check on http://localhost:{httpserver.port}/ ...
71+
SUCCESS test1
72+
reason1
73+
data1
74+
ERROR test2
75+
reason2
76+
data2
77+
"""
78+
assert result.output == expected_output

0 commit comments

Comments
 (0)