def test_number_deserializing(testdir): # When numbers in schema are written in scientific notation but without a dot (achieved by dumping the schema with json.dumps) schema = { "openapi": "3.0.2", "info": {"title": "Test", "description": "Test", "version": "0.1.0"}, "paths": { "/teapot": { "get": { "summary": "Test", "parameters": [ { "name": "key", "in": "query", "required": True, "schema": {"type": "number", "multipleOf": 0.00001,}, } ], "responses": {"200": {"description": "OK"}}, } } }, } schema_path = testdir.makefile(".yaml", schema=json.dumps(schema)) # Then yaml loader should parse them without schema validation errors parsed = schemathesis.from_path(str(schema_path)) # and the value should be a number value = parsed.raw_schema["paths"]["/teapot"]["get"]["parameters"][0]["schema"]["multipleOf"] assert isinstance(value, float)
def test_response_schema_conformance_references_invalid(complex_schema): schema = schemathesis.from_path(complex_schema) @given(case=schema.endpoints["/teapot"]["POST"].as_strategy()) @settings(max_examples=3) def test(case): response = make_response(json.dumps({"foo": 1}).encode()) with pytest.raises(AssertionError): case.validate_response(response)
def test_response_schema_conformance_references_valid(complex_schema, value): schema = schemathesis.from_path(complex_schema) @given(case=schema.endpoints["/teapot"]["POST"].as_strategy()) @settings(max_examples=3) def test(case): response = make_response(json.dumps({"key": value, "referenced": value}).encode()) case.validate_response(response) test()
def test_date_deserializing(testdir): # When dates in schema are written without quotes (achieved by dumping the schema with date instances) schema = { "openapi": "3.0.2", "info": { "title": "Test", "description": "Test", "version": "0.1.0" }, "paths": { "/teapot": { "get": { "summary": "Test", "parameters": [{ "name": "key", "in": "query", "required": True, "schema": { "allOf": [ # For sake of example to check allOf logic { "type": "string", "example": datetime.date(2020, 1, 1) }, { "type": "string", "example": datetime.date(2020, 1, 1) }, ] }, }], "responses": { "200": { "description": "OK" } }, } } }, } schema_path = testdir.makefile(".yaml", schema=yaml.dump(schema)) # Then yaml loader should ignore it # And data generation should work without errors schema = schemathesis.from_path(str(schema_path)) @given(case=schema["/teapot"]["GET"].as_strategy()) @settings(suppress_health_check=[HealthCheck.filter_too_much]) def test(case): assert isinstance(case.query["key"], str) test()
def test_path_loader(simple_schema): # Each loader method should read the specified schema correctly assert schemathesis.from_path(SIMPLE_PATH).raw_schema == simple_schema
def test_complex_dereference(testdir): # This tests includes: # - references to other files # - local references in referenced files # - different directories - relative paths to other files schema_root = testdir.mkdir("root") common = testdir.mkdir("common") paths = schema_root.mkdir("paths") schemas = schema_root.mkdir("schemas") teapot_schemas = schemas.mkdir("teapot") root = schema_root / "root.yaml" root.write_text(yaml.dump(ROOT_SCHEMA), "utf8") (paths / "teapot.yaml").write_text(yaml.dump(TEAPOT_PATHS), "utf8") (teapot_schemas / "create.yaml").write_text(yaml.dump(TEAPOT_CREATE_SCHEMAS), "utf8") (common / "responses.yaml").write_text(yaml.dump(COMMON_RESPONSES), "utf8") schema = schemathesis.from_path(str(root)) assert schema.endpoints["/teapot"]["POST"] == Endpoint( path="/teapot", method="POST", definition={ "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": False, "description": "Test", "properties": { "profile": { "additionalProperties": False, "description": "Test", "properties": {"id": {"type": "integer"}}, "required": ["id"], "type": "object", }, "username": {"type": "string"}, }, "required": ["username", "profile"], "type": "object", } } }, "description": "Test.", "required": True, }, "responses": { "default": { "content": { "application/json": { "schema": { "additionalProperties": False, "properties": {"key": {"type": "string"}}, "required": ["key"], "type": "object", } } }, "description": "Probably an error", } }, "summary": "Test", "tags": ["ancillaries"], }, body={ "additionalProperties": False, "description": "Test", "properties": { "profile": { "additionalProperties": False, "description": "Test", "properties": {"id": {"type": "integer"}}, "required": ["id"], "type": "object", }, "username": {"type": "string"}, }, "required": ["username", "profile"], "type": "object", }, schema=schema, )
resp_len=str(len(response.text)), scope=cred_set['scope'], username=credential, # snapmortgage method="GET") result_md += single_result #targeted_endpoint = {"/orgs/{org}/repos":{"type":"all"}} return result_md ## Initiate the variables base_url = os.getenv('OPENAPI_BASE_URL') targeted_endpoints = json.loads(os.getenv('OPENAPI_ENDPOINTS')) path_examples = json.loads(os.getenv('OPENAPI_PATHS')) credentials = json.loads(os.getenv('OPENAPI_CREDS')) schema = schemathesis.from_path("api.yaml", base_url=base_url) divider = "|" md_header = "| - | Status | Length | Scope | Username | Method |\n" + "| - | - | - | - | - | -|\n" ## Make path_examples to become a list with all possible combinations path_examples = expand_paths_to_list(path_examples) for path_param in path_examples: md_header += main(path_param) result_response = requests.post(json={"text": md_header}, url="https://gitlab.com/api/v4/markdown") result_json = json.loads(result_response.text) html = result_json['html']
import pytest import requests import schemathesis from hypothesis import settings from requests.auth import HTTPBasicAuth BASE_URL = 'http://127.0.0.1:8000/api/v1' schema = schemathesis.from_path('api_schemas/API-schema-users.json') @pytest.fixture def session(): with requests.Session() as s: data = {"email": "*****@*****.**", "password": "******"} auth_response = s.post(f'{BASE_URL}/login', data=data) token = auth_response.json()['token'] s.headers['Authorization'] = f'Token {token}' yield s @settings(max_examples=1) @schema.parametrize() def test_no_server_errors(case, session): print(session.headers) response = requests.request(case.method, f'{BASE_URL}{case.formatted_path}', headers=session.headers, params=case.query, json=case.body) assert response.status_code < 500
kwargs = {"endpoint": endpoint} if override: case = Case(**kwargs) response = case.call(base_url) else: case = Case(**kwargs) endpoint.base_url = base_url response = case.call() assert response.status_code == 200 assert response.json() == {"success": True} with pytest.warns(None) as records: del response assert not records schema = schemathesis.from_path(SIMPLE_PATH) ENDPOINT = Endpoint("/api/success", "GET", {}, base_url="http://example.com", schema=schema) @pytest.mark.parametrize( "case, expected", ( (Case(ENDPOINT, body={"test": 1}), "requests.get('http://example.com/api/success', json={'test': 1})"), (Case(ENDPOINT), "requests.get('http://example.com/api/success')"), (Case(ENDPOINT, query={"a": 1}), "requests.get('http://example.com/api/success', params={'a': 1})"), ), ) def test_get_code_to_reproduce(case, expected): assert case.get_code_to_reproduce() == expected
def test_complex_dereference(testdir, complex_schema): schema = schemathesis.from_path(complex_schema) path = Path(str(testdir)) body_definition = { "schema": { "additionalProperties": False, "description": "Test", "properties": { "profile": { "additionalProperties": False, "description": "Test", "properties": {"id": {"type": "integer"}}, "required": ["id"], "type": "object", }, "username": {"type": "string"}, }, "required": ["username", "profile"], "type": "object", } } operation = schema["/teapot"]["POST"] assert operation.base_url == "file:///" assert operation.path == "/teapot" assert operation.method == "post" assert len(operation.body) == 1 assert operation.body[0].required assert operation.body[0].media_type == "application/json" assert operation.body[0].definition == body_definition assert operation.definition.raw == { "requestBody": { "content": {"application/json": {"schema": {"$ref": "../schemas/teapot/create.yaml#/TeapotCreateRequest"}}}, "description": "Test.", "required": True, }, "responses": {"default": {"$ref": "../../common/responses.yaml#/DefaultError"}}, "summary": "Test", "tags": ["ancillaries"], } assert operation.definition.resolved == { "requestBody": { "content": {"application/json": body_definition}, "description": "Test.", "required": True, }, "responses": { "default": { "content": { "application/json": { "schema": { "additionalProperties": False, "properties": { # Note, these `nullable` keywords are not transformed at this point # It is done during the response validation. "key": {"type": "string", "nullable": True}, "referenced": {"type": "string", "nullable": True}, }, "required": ["key", "referenced"], "type": "object", } } }, "description": "Probably an error", } }, "summary": "Test", "tags": ["ancillaries"], } assert operation.definition.scope == f"{path.as_uri()}/root/paths/teapot.yaml#/TeapotCreatePath" assert len(operation.definition.parameters) == 1 assert operation.definition.parameters[0].required assert operation.definition.parameters[0].media_type == "application/json" assert operation.definition.parameters[0].definition == body_definition
def test_complex_dereference(testdir, complex_schema): schema = schemathesis.from_path(complex_schema) path = Path(str(testdir)) body = OpenAPI30Body( { "schema": { "additionalProperties": False, "description": "Test", "properties": { "profile": { "additionalProperties": False, "description": "Test", "properties": {"id": {"type": "integer"}}, "required": ["id"], "type": "object", }, "username": {"type": "string"}, }, "required": ["username", "profile"], "type": "object", } }, required=True, media_type="application/json", ) assert schema.endpoints["/teapot"]["POST"] == Endpoint( base_url="file:///", path="/teapot", method="post", definition=EndpointDefinition( { "requestBody": { "content": { "application/json": {"schema": {"$ref": "../schemas/teapot/create.yaml#/TeapotCreateRequest"}} }, "description": "Test.", "required": True, }, "responses": {"default": {"$ref": "../../common/responses.yaml#/DefaultError"}}, "summary": "Test", "tags": ["ancillaries"], }, { "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": False, "description": "Test", "properties": { "profile": { "additionalProperties": False, "description": "Test", "properties": {"id": {"type": "integer"}}, "required": ["id"], "type": "object", }, "username": {"type": "string"}, }, "required": ["username", "profile"], "type": "object", } } }, "description": "Test.", "required": True, }, "responses": { "default": { "content": { "application/json": { "schema": { "additionalProperties": False, "properties": { "key": {"anyOf": [{"type": "string"}, {"type": "null"}]}, "referenced": {"anyOf": [{"type": "string"}, {"type": "null"}]}, }, "required": ["key", "referenced"], "type": "object", } } }, "description": "Probably an error", } }, "summary": "Test", "tags": ["ancillaries"], }, scope=f"{path.as_uri()}/root/paths/teapot.yaml#/TeapotCreatePath", parameters=[body], ), body=PayloadAlternatives([body]), schema=schema, )
from hypothesis import settings import schemathesis import os abs_file_path = os.path.abspath(os.path.dirname(__file__)) openapi_path = os.path.join(abs_file_path, "../", "static/schema.json") schema = schemathesis.from_path(openapi_path, base_url="http://localhost:57244") @schema.parametrize() @settings(max_examples=20) def test_no_server_errors_uri(case, test_server): response = case.call() assert response.status_code in [200, 201, 400]
def schema_app(app): from example_app.openapi import OAS_PATH return schemathesis.from_path(OAS_PATH, app=app)
import pytest import requests import schemathesis from hypothesis import settings from requests.auth import HTTPBasicAuth BASE_URL = 'http://127.0.0.1:8000/api/v1' schema = schemathesis.from_path('api_schemas/API-schema-search.json') @pytest.fixture def session(): with requests.Session() as s: data = {"email": "*****@*****.**", "password": "******"} auth_response = s.post(f'{BASE_URL}/login', data=data) token = auth_response.json()['token'] s.headers['Authorization'] = f'Token {token}' yield s @settings(max_examples=1) @schema.parametrize() def test_no_server_errors(case, session): print(session.headers) response = requests.request(case.method, f'{BASE_URL}{case.formatted_path}', headers=session.headers, params=case.query, json=case.body) assert response.status_code < 500
import pytest import requests import schemathesis from hypothesis import settings from requests.auth import HTTPBasicAuth BASE_URL = "http://127.0.0.1:8000/api/v1" schema = schemathesis.from_path('api_schemas/API-schema-login.json') @settings(max_examples=2) @schema.parametrize() def test_no_server_errors(case): response = requests.request( case.method, f"{BASE_URL}{case.formatted_path}", headers=case.headers, params=case.query, json={"email": "*****@*****.**", "password": "******"}, ) assert response.status_code < 500
# test.py import schemathesis schema = schemathesis.from_path('./todo.yaml') schema.base_url = 'http://localhost:8080' @schema.parametrize() def test_time(case): response = case.call() assert response.elapsed.total_seconds() < 1