Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,12 @@ jobs:

- name: Build and run docker test image
run: uv run inv test-app

- name: Create libdoc
run: uv run inv docs

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: SchemathesisLibrary-${{ matrix.python-version }}.html
path: docs/SchemathesisLibrary.html
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ wheels/

# pytest
.pytest_cache/

# Robot Framework
atest/output

# VS Code
.vscode/
61 changes: 57 additions & 4 deletions SchemathesisLibrary/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,79 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import schemathesis
from hypothesis import given, settings, HealthCheck, Phase, Verbosity
from DataDriver import DataDriver # type: ignore
from robot.api.deco import keyword
from robot.running.model import TestCase, TestSuite # type: ignore
from robot.result.model import TestSuite as ResultTestSuite # type: ignore
from robot.result.model import TestCase as ResultTestCase # type: ignore
from robotlibcore import DynamicCore # type: ignore
from DataDriver.AbstractReaderClass import AbstractReaderClass # type: ignore
from DataDriver.ReaderConfig import TestCaseData # type: ignore

__version__ = "0.1.0"


class SchemathesisLibrary:
class SchemathesisReader(AbstractReaderClass):
def __init__(self, *, url: "str|None" = None):
self.url = url

def get_data_from_source(
self,
): # This method will be called from DataDriver to get the TestCaseData list.
schema = schemathesis.from_uri(self.url)
all_cases = []
for op in schema.get_all_operations():
op_as_strategy = op.ok().as_strategy()
for case in generate_examples(op_as_strategy, 10):
args = {
"${case}": case,
}
all_cases.append(
TestCaseData(test_case_name=str(case.id), arguments=args)
)
return all_cases


class SchemathesisLibrary(DynamicCore):
ROBOT_LIBRARY_VERSION = __version__
ROBOT_LISTENER_API_VERSION = 3
ROBOT_LIBRARY_SCOPE = "TEST SUITE"

def __init__(self):
def __init__(self, *, url: "str|None" = None):
self.ROBOT_LIBRARY_LISTENER = self
self.data_driver = DataDriver()
self.data_driver = DataDriver(
reader_class=SchemathesisReader(url=url), file_regex=""
)
DynamicCore.__init__(self, [])

def _start_suite(self, data: TestSuite, result: ResultTestSuite):
self.data_driver._start_suite(data, result)

def _start_test(self, data: TestCase, result: ResultTestCase):
self.data_driver._start_test(data, result)

@keyword
def call_and_validate(self, case: schemathesis.Case) -> None:
"""Validate a Schemathesis case."""
case.call_and_validate()


def generate_examples(strategy, number) -> list[schemathesis.Case]:
examples = []

@given(strategy)
@settings(
database=None,
max_examples=number,
deadline=None,
verbosity=Verbosity.quiet,
phases=(Phase.generate,),
suppress_health_check=list(HealthCheck),
)
def example_generating_inner_function(ex):
examples.append(ex)

example_generating_inner_function()
return examples
15 changes: 15 additions & 0 deletions atest/test/all_cases.robot
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
*** Settings ***
Library SchemathesisLibrary

Test Template Wrapper


*** Test Cases ***
All Tests
Wrapper test_case_1


*** Keywords ***
Wrapper
[Arguments] ${case}
Run And Validate ${case}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ requires-python = ">=3.10.1"
dependencies = [
"robotframework>=7.2.2",
"robotframework-datadriver>=1.11.2",
"robotframework-pythonlibcore>=4.4.1",
"schemathesis>=3.39.16",
]

Expand Down
39 changes: 38 additions & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@

import requests
from invoke.tasks import task
from robot.libdoc import libdoc

ROOT = Path(__file__).parent
ROOT_DIR = Path(__file__).parent
ATEST_OUTPUT_DIR = ROOT_DIR / "atest" / "output"
DOCKER_IMAGE = "schemathesis-library-test"
DOCKER_CONTAINER = "schemathesis-library-test-app"

Expand Down Expand Up @@ -69,3 +71,38 @@ def test_app(ctx):
print(f"Connection error: {error}")
if i == 299:
raise RuntimeError("Test app did not start in time")


@task
def docs(ctx, version: str | None = None):
"""Generate library keyword documentation.

Args:
version: Creates keyword documentation with version
suffix in the name. Documentation is moved to docs/vesions
folder.
"""
output = ROOT_DIR / "docs" / "SchemathesisLibrary.html"
libdoc("SchemathesisLibrary", str(output))
if version is not None:
target = (
ROOT_DIR / "docs" / "versions" / f"SchemathesisLibrary-{version.replace('v', '')}.html"
)
output.rename(target)


@task
def atest(ctx):
"""Run acceptance tests."""
args = [
"uv",
"run",
"robot",
"--pythonpath",
".",
"--outputdir",
ATEST_OUTPUT_DIR.as_posix(),
"atest/test",
]
ATEST_OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
ctx.run(" ".join(args))
11 changes: 11 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.