Skip to content

Commit

Permalink
Restructure CLI & add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitry Dygalo authored and paveldedik committed Oct 4, 2019
1 parent 45a761a commit 2d0b6a6
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 42 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pytest-mock = "^1.11.0"
pytest11 = {schemathesis = "schemathesis.extra.pytest_plugin"}

[tool.poetry.scripts]
schemathesis = "schemathesis.commands:main"
schemathesis = "schemathesis.cli:main"

[tool.black]
line-length = 120
Expand Down
45 changes: 7 additions & 38 deletions src/schemathesis/commands.py → src/schemathesis/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from contextlib import contextmanager
from typing import Dict, Generator, Iterable, Optional, Tuple
from urllib.parse import urlparse
from typing import Dict, Iterable, Optional, Tuple

import click

from . import runner
from .types import Filter
from .. import runner
from ..types import Filter
from . import validators

CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])

Expand All @@ -18,35 +17,8 @@ def main() -> None:
"""Command line tool for testing your web application built with Open API / Swagger specifications."""


def validate_auth(
ctx: click.core.Context, param: click.core.Option, raw_value: Optional[str]
) -> Optional[Tuple[str, str]]:
if raw_value is not None:
with reraise_format_error(raw_value):
user, password = tuple(raw_value.split(":"))
return user, password
return None


def validate_headers(ctx: click.core.Context, param: click.core.Option, raw_value: Tuple[str, ...]) -> Dict[str, str]:
headers = {}
for header in raw_value:
with reraise_format_error(header):
key, value = header.split(":")
headers[key] = value.lstrip()
return headers


@contextmanager
def reraise_format_error(raw_value: str) -> Generator:
try:
yield
except ValueError:
raise click.BadParameter(f"Should be in KEY:VALUE format. Got: {raw_value}")


@main.command(short_help="Perform schemathesis test.")
@click.argument("schema", type=str)
@click.argument("schema", type=str, callback=validators.validate_schema) # type: ignore
@click.option(
"--checks",
"-c",
Expand All @@ -60,7 +32,7 @@ def reraise_format_error(raw_value: str) -> Generator:
"-a",
help="Server user and password. Example: USER:PASSWORD",
type=str,
callback=validate_auth, # type: ignore
callback=validators.validate_auth, # type: ignore
)
@click.option( # type: ignore
"--header",
Expand All @@ -69,7 +41,7 @@ def reraise_format_error(raw_value: str) -> Generator:
help=r"Custom header in a that will be used in all requests to the server. Example: Authorization: Bearer\ 123",
multiple=True,
type=str,
callback=validate_headers, # type: ignore
callback=validators.validate_headers, # type: ignore
)
@click.option(
"--endpoint",
Expand All @@ -92,9 +64,6 @@ def run( # pylint: disable=too-many-arguments
SCHEMA must be a valid URL pointing to an Open API / Swagger specification.
"""
if not urlparse(schema).netloc:
raise click.UsageError("Invalid SCHEMA, must be a valid URL.")

selected_checks = tuple(check for check in runner.DEFAULT_CHECKS if check.__name__ in checks)

click.echo("Running schemathesis test cases ...")
Expand Down
38 changes: 38 additions & 0 deletions src/schemathesis/cli/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from contextlib import contextmanager
from typing import Dict, Generator, Optional, Tuple
from urllib.parse import urlparse

import click


def validate_schema(ctx: click.core.Context, param: click.core.Option, raw_value: str) -> str:
if not urlparse(raw_value).netloc:
raise click.UsageError("Invalid SCHEMA, must be a valid URL.")
return raw_value


def validate_auth(
ctx: click.core.Context, param: click.core.Option, raw_value: Optional[str]
) -> Optional[Tuple[str, str]]:
if raw_value is not None:
with reraise_format_error(raw_value):
user, password = tuple(raw_value.split(":"))
return user, password
return None


def validate_headers(ctx: click.core.Context, param: click.core.Option, raw_value: Tuple[str, ...]) -> Dict[str, str]:
headers = {}
for header in raw_value:
with reraise_format_error(header):
key, value = header.split(":")
headers[key] = value.lstrip()
return headers


@contextmanager
def reraise_format_error(raw_value: str) -> Generator:
try:
yield
except ValueError:
raise click.BadParameter(f"Should be in KEY:VALUE format. Got: {raw_value}")
Empty file added test/cli/__init__.py
Empty file.
6 changes: 3 additions & 3 deletions test/test_commands.py → test/cli/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from click.testing import CliRunner

from schemathesis import commands, runner
from schemathesis import cli, runner


@pytest.fixture()
Expand Down Expand Up @@ -137,10 +137,10 @@ def test_commands_run_help(schemathesis_cmd):
)
def test_commands_run(mocker, args, expected):
m_execute = mocker.patch("schemathesis.runner.execute")
cli = CliRunner()
cli_runner = CliRunner()

schema_uri = "https://example.com/swagger.json"
result = cli.invoke(commands.run, args)
result = cli_runner.invoke(cli.run, args)

assert result.exit_code == 0
m_execute.assert_called_once_with(schema_uri, **expected)
Expand Down
30 changes: 30 additions & 0 deletions test/cli/test_validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import click
import pytest
from hypothesis import given
from hypothesis import strategies as st

from schemathesis.cli import validators


@given(value=st.text())
def test_validate_schema(value):
with pytest.raises(click.UsageError):
validators.validate_schema(None, None, value)


@given(value=st.text())
def test_validate_auth(value):
with pytest.raises(click.BadParameter):
validators.validate_auth(None, None, value)


@given(value=st.lists(st.text(), min_size=1).map(tuple))
def test_validate_header(value):
with pytest.raises(click.BadParameter):
validators.validate_headers(None, None, value)


def test_reraise_format_error():
with pytest.raises(click.BadParameter, match="Should be in KEY:VALUE format. Got: bla"):
with validators.reraise_format_error("bla"):
raise ValueError

0 comments on commit 2d0b6a6

Please sign in to comment.