def test_fake_array(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/items", host="api.com") ) schema = {"type": "array", "items": {"$ref": "#/components/schemas/item"}} components = { "schemas": { "item": { "type": "object", "required": ["foo", "bar"], "x-hmt-id-path": "itemId", "properties": { "foo": {"type": "number"}, "bar": {"type": "string"}, "itemId": {"type": "string"}, }, } } } spec = spec_dict( path="/items", response_schema=schema, components=components, method="get" ) spec["paths"]["/items"]["x-hmt-entity"] = "item" spec["paths"]["/items"]["get"]["x-hmt-operation"] = "read" spec = convert_to_OpenAPIObject(spec) mock_data_store.add_mock(OpenAPISpecification(spec, "default")) schema["components"] = components spec = OpenAPISpecification(source="default", api=spec) res = faker.process(spec, request) assert valid_schema(res.bodyAsJson, schema) assert 0 == len(res.bodyAsJson) mock_data_store["default"].item.insert({"foo": 10, "bar": "val", "itemId": "id123"}) res = faker.process(spec, request) assert valid_schema(res.bodyAsJson, schema) assert 1 == len(res.bodyAsJson) mock_data_store["default"].item.insert( {"foo": 10, "bar": "val", "itemId": "id1234"} ) res = faker.process(spec, request) assert valid_schema(res.bodyAsJson, schema) assert 2 == len(res.bodyAsJson)
def test_sateless_faker_2(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com") ) schema = { "$id": "https://example.com/person.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Person", "type": "object", "properties": { "firstName": {"type": "string", "description": "The person's first name."}, "lastName": {"type": "string", "description": "The person's last name."}, "age": { "description": "Age in years which must be equal to or greater than zero.", "type": "integer", "minimum": 0.0, }, }, } res = faker.process( OpenAPISpecification(source="default", api=spec(response_schema=schema)), request, ) assert valid_schema(res.bodyAsJson, schema)
def test_sateless_faker_3(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com") ) schema = { "$id": "https://example.com/geographical-location.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Longitude and Latitude Values", "description": "A geographical coordinate.", "required": ["latitude", "longitude"], "type": "object", "properties": { "latitude": {"type": "number", "minimum": -90.0, "maximum": 90.0}, "longitude": {"type": "number", "minimum": -180.0, "maximum": 180.0}, }, } res = faker.process( OpenAPISpecification(source="default", api=spec(response_schema=schema)), request, ) assert valid_schema(res.bodyAsJson, schema)
def test_clear(): store = MockDataStore() store.add_mock(OpenAPISpecification(spec(), "pokemon")) store.add_mock(OpenAPISpecification(spec(), "another")) store["pokemon"]["x"] = "foo" store["another"]["y"] = "bar" assert "foo" == store["pokemon"]["x"] assert "bar" == store["another"]["y"] store.clear() assert store["pokemon"].get("x") is None assert store["another"].get("y") is None
def test_sateless_faker_1(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com") ) schema = { "type": "array", "items": { "type": "object", "required": ["foo", "baz"], "properties": { "foo": {"type": "number"}, "bar": {"type": "string"}, "baz": {"type": "string"}, }, }, } res = faker.process( OpenAPISpecification(source="default", api=spec(response_schema=schema)), request, ) assert valid_schema(res.bodyAsJson, schema)
def test_add_mock_no_data(): schema = {"$ref": "#/components/schemas/item"} components = { "schemas": { "item": { "type": "object", "required": ["foo", "baz"], "x-hmt-id-path": "itemId", "properties": { "foo": {"type": "number"}, "bar": {"type": "string"}, "itemId": {"type": "string"}, }, } } } spec = spec_dict( path="/items/{id}", response_schema=schema, components=components, method="get" ) spec["paths"]["/items/{id}"]["x-hmt-entity"] = "item" spec["paths"]["/items/{id}"]["get"]["x-hmt-operation"] = "read" spec = convert_to_OpenAPIObject(spec) store = MockDataStore() store.add_mock(OpenAPISpecification(spec, "items")) assert 0 == len(store["items"].item) store["items"].item.insert({"foo": 10, "bar": "val", "itemId": "id123"}) assert 1 == len(store["items"].item) assert "val" == store["items"].item["id123"]["bar"]
def match_request_to_openapi( req: Request, specs: Sequence[OpenAPISpecification] ) -> Sequence[OpenAPISpecification]: def _path_item_modifier( oai: OpenAPIObject) -> Callable[[PathItem], PathItem]: def __path_item_modifier(path_item: PathItem) -> PathItem: return reduce( lambda a, b: b(a), [ keep_method_if_required_header_parameters_are_present( req, oai), keep_method_if_required_query_parameters_are_present( req, oai), ##### keep_method_if_required_request_body_is_present ##### should be uncommented in a separate PR ##### it breaks the logic in the new schemabuilder ##### but it should be reimplemented ##### now, the issue is that API requests will not ##### have their body validated ##### as there are so few API requests that require body ##### validation for mocking, this is a small loss ##### but should still be acknowledged and fixed when ##### someone has time # keep_method_if_required_request_body_is_present(req, oai), ], get_path_item_with_method(req.method.value, path_item), ) return __path_item_modifier def _oai_modifier(oai: OpenAPIObject) -> OpenAPIObject: return paths_o.Values().modify(_path_item_modifier(oai))(replace( oai, paths={ n: o for n, o in oai.paths.items() if matches( truncate_path(req.pathname, oai, req), n, o, req.method.value, oai, ) }, )) specs_with_matching_urls = { spec.source: spec.api for spec in specs if len(match_urls(req.protocol.value, req.host, spec.api)) > 0 } filtered = { k: _oai_modifier(v) for k, v in specs_with_matching_urls.items() } return [ OpenAPISpecification(api, source) for (source, api) in filtered.items() ]
def test_sateless_faker_4(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com")) schema = { "$id": "https://example.com/arrays.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "description": "A representation of a person, company, organization, or place", "type": "object", "properties": { "fruits": { "type": "array", "items": { "type": "string" } }, "vegetables": { "type": "array", "items": { "$ref": "#/components/schemas/veggie" }, }, }, } components = { "schemas": { "veggie": { "type": "object", "required": ["veggieName", "veggieLike"], "properties": { "veggieName": { "type": "string", "description": "The name of the vegetable.", }, "veggieLike": { "type": "boolean", "description": "Do I like this vegetable?", }, }, } } } oai = spec(response_schema=schema, components=components) res = faker.process( "/", OpenAPISpecification(source="default", api=oai, definitions=make_definitions_from_spec(oai)), request, ) schema["components"] = components assert valid_schema(res.bodyAsJson, schema)
def test_sateless_faker_5(mock_data_store): faker = StatefulFaker(mock_data_store) request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com") ) schema = {"type": "array"} res = faker.process( OpenAPISpecification(source="default", api=spec(response_schema=schema)), request, ) assert valid_schema(res.bodyAsJson, schema)
def test_storage(mock_data_store, http_client, base_url): schema = {"$ref": "#/components/schemas/item"} components = { "schemas": { "item": { "type": "object", "required": ["foo", "baz"], "x-hmt-id-path": "itemId", "properties": { "foo": {"type": "number"}, "bar": {"type": "string"}, "itemId": {"type": "string"}, }, } } } spec = spec_dict( path="/items/{id}", response_schema=schema, components=components, method="get" ) spec["paths"]["/items/{id}"]["x-hmt-entity"] = "item" spec["paths"]["/items/{id}"]["get"]["x-hmt-operation"] = "read" spec["x-hmt-data"] = {"item": [{"foo": 10, "bar": "val", "itemId": "id123"}]} spec = convert_to_OpenAPIObject(spec) mock_data_store.add_mock(OpenAPISpecification(spec, "items")) req = HTTPRequest(base_url + "/admin/storage", method="DELETE") response = yield http_client.fetch(req) assert response.code == 200 assert 0 == len(mock_data_store["items"].item) req = HTTPRequest(base_url + "/admin/storage/reset", method="POST", body="") response = yield http_client.fetch(req) assert response.code == 200 assert 1 == len(mock_data_store["items"].item) with pytest.raises(HTTPClientError): req = HTTPRequest(base_url + "/admin/storage/reset", method="DELETE") response = yield http_client.fetch(req) assert 1 == len(mock_data_store["items"].item)
def test_faker_5(): faker = StatelessFaker() request = RequestBuilder.from_dict( dict(method="get", protocol="http", path="/", host="api.com") ) schema = {"type": "array"} res = faker.process( "/", OpenAPISpecification( source="default", api=spec(response_schema=schema), definitions={"definitions": {}}, ), request, ) assert valid_schema(res.bodyAsJson, schema)
def spew( self, request: Request, specs: Sequence[OpenAPISpecification] ) -> Sequence[OpenAPISpecification]: if len(self._endpoints) == 0: return specs req = HttpExchangeWriter.to_dict(request) cs = {spec.source: convert_from_openapi(spec.api) for spec in specs} for endpoint in self._endpoints: res = requests.post(endpoint, json={"request": req, "schemas": cs}) cs = res.json() out = [ OpenAPISpecification(convert_to_openapi(dict_spec), name) for name, dict_spec in cs.items() ] for spec in out: self._mock_data_store.add_mock(spec) return out
def test_insert(mock_data_store): faker = StatefulFaker(mock_data_store) request_schema = { "type": "object", "properties": {"item": {"$ref": "#/components/schemas/item"}}, } response_schema = {"$ref": "#/components/schemas/item"} components = { "schemas": { "item": { "type": "object", "required": ["foo"], "x-hmt-id-path": "itemId", "properties": { "foo": {"type": "number"}, "bar": {"type": "string"}, "baz": {"type": "string"}, "itemId": {"type": "string"}, }, } } } spec = spec_dict( path="/items", request_schema=request_schema, response_schema=response_schema, components=components, method="post", ) spec["paths"]["/items"]["x-hmt-entity"] = "item" spec["paths"]["/items"]["post"]["x-hmt-operation"] = "insert" spec = convert_to_OpenAPIObject(spec) mock_data_store.add_mock(OpenAPISpecification(spec, "default")) schema = response_schema schema["components"] = components spec = OpenAPISpecification(source="default", api=spec) request = RequestBuilder.from_dict( dict( method="post", protocol="http", path="/items", host="api.com", bodyAsJson={"item": {"foo": 10, "bar": "val"}}, ) ) res = faker.process(spec, request) assert valid_schema(res.bodyAsJson, schema) assert res.bodyAsJson["itemId"] is not None assert 10 == res.bodyAsJson["foo"] assert 1 == len(mock_data_store["default"].item) assert "val" == mock_data_store["default"].item[res.bodyAsJson["itemId"]]["bar"] request = RequestBuilder.from_dict( dict( method="post", protocol="http", path="/items", host="api.com", bodyAsJson={"item": {"foo": 20, "bar": "val1", "itemId": "id123"}}, ) ) res = faker.process(spec, request) assert valid_schema(res.bodyAsJson, schema) assert "id123" == res.bodyAsJson["itemId"] assert 20 == res.bodyAsJson["foo"] assert 2 == len(mock_data_store["default"].item) assert "val1" == mock_data_store["default"].item[res.bodyAsJson["itemId"]]["bar"] request = RequestBuilder.from_dict( dict( method="post", protocol="http", path="/items", host="api.com", bodyAsJson={"item": {"foo": 30, "itemId": "id123"}}, ) ) res = faker.process(spec, request) assert 2 == len(mock_data_store["default"].item) assert "bar" not in mock_data_store["default"].item[res.bodyAsJson["itemId"]] assert 30 == mock_data_store["default"].item[res.bodyAsJson["itemId"]]["foo"]
OpenAPISpecification( convert_to_openapi({ "openapi": "", "servers": [{ "url": "api.foo.com" }], # we omit the protocol and it should still match "info": { "title": "", "version": "" }, "paths": { "/user": { "get": { "responses": { "200": { "description": "userget" } } }, "post": { "responses": { "200": { "description": "userpost" } } }, "description": "", }, "/user/{id}": { "parameters": [ { "name": "id", "in": "path", "required": True, "schema": { "type": "integer" }, }, ], "get": { "responses": { "200": { "description": "useridget" } } }, "post": { "responses": { "201": { "description": "useridpost" } } }, }, "/user/{id}/name": { "get": { "responses": { "200": { "description": "useridnameget" } } }, "post": { "responses": { "201": { "description": "useridnamepost" } } }, "description": "", }, }, }), "foo", {"definitions": {}}, ),