def test_matcher(): _bfoo = { "parameters": [ { "in": "path", "name": "foo", "schema": {"type": "string", "pattern": "^[abc]+$"}, }, ], "get": { "responses": { "200": {"description": "some", "content": {"application/json": {}},} } }, } bfoo = convert_to_PathItem(_bfoo) oai: OpenAPIObject = convert_to_openapi( { "openapi": "", "info": {"title": "", "version": ""}, "paths": {"/b/{foo}": _bfoo}, } ) assert matches(["a", "b"], "/a/b", bfoo, "get") assert not matches(["a"], "/a/b", bfoo, "get") assert not matches(["a", "b"], "/a", bfoo, "get") assert matches(["a", "b", "c"], "/a/{fewfwef}/c", bfoo, "get") assert matches(["b", "ccaaca"], "/b/{foo}", bfoo, "get") assert matches(["b", "ccaaca"], "/b/{foo}", bfoo, "get") assert not matches(["a", "b", "c"], "/a/{fewfwef}/c", bfoo, "post")
def build(input_file, out, initial_openapi_spec, mode, source): """ Build an OpenAPI specification from HTTP recordings. """ if input_file is not None and source != "file": raise Exception("Only specify input-file for --source file") sinks = [FileSystemSink(out)] if source == "kafka": # TODO Kafka configuration source = KafkaSource( config=KafkaSourceConfig(broker="localhost:9092", topic="http_recordings") ) elif source == "file": if input_file is None: raise Exception("Option --input-file for source 'file' required.") source = FileSource(input_file) else: raise Exception("Unknown source {}".format(source)) openapi_spec: OpenAPIObject = BASE_SCHEMA if initial_openapi_spec is not None: try: maybe_openapi = safe_load(initial_openapi_spec.read()) # will raise if not an API spec openapi_spec = convert_to_openapi(maybe_openapi) except Exception: pass # just use the initial schema run_from_source(source, UpdateMode[mode.upper()], openapi_spec, sinks=sinks)
def test_match_urls(): assert ["https://api.foo.com"] == match_urls( "https", "api.foo.com", convert_to_openapi( { "openapi": "", "paths": {}, "info": {"title": "", "version": ""}, "servers": [ {"url": "https://api.foo.commm/v2"}, {"url": "https://api.foo.com"}, ], } ), ) assert ["https://api.foo.com/v2/a/b/c"] == match_urls( "https", "api.foo.com", convert_to_openapi( { "openapi": "", "paths": {}, "info": {"title": "", "version": ""}, "servers": [ {"url": "https://api.foo.commm/v2"}, {"url": "https://api.foo.com/v2/a/b/c"}, ], } ), ) assert [] == match_urls( "https", "api.foo.com/v2", convert_to_openapi( { "openapi": "", "paths": {}, "info": {"title": "", "version": ""}, "servers": [ {"url": "https://api.foo.commm/v2"}, {"url": "https://api.foo.cooom/v2"}, ], } ), )
def test_request_logging_mixed_append(tmp_dir): specs_dir = os.path.join(tmp_dir, "specs") spec_path = os.path.join(specs_dir, "another.api.com_mixed.json") os.makedirs(specs_dir) with open(spec_path, "w") as f: json.dump(convert_from_openapi(BASE_SCHEMA), f) with open(spec_path) as f: spec = convert_to_openapi(json.load(f)) assert spec.servers is None request = RequestBuilder.from_dict( dict( method="get", host="another.api.com", pathname="/echo", query={"message": "Hello"}, body="", bodyAsJson={}, path="/echo", protocol="http", headers={}, )) response = ResponseBuilder.from_dict( dict( statusCode=200, body='{"message": "hello"}', bodyAsJson={"message": "hello"}, headers={}, )) log_dir = os.path.join(tmp_dir, "logs") with RequestLoggingCallback(log_dir=log_dir, specs_dir=specs_dir, update_mode=UpdateMode.MIXED) as data_callback: data_callback.log(request, response) assert os.path.exists( os.path.join(log_dir, "another.api.com-recordings.jsonl")) assert os.path.exists(spec_path) with open(spec_path) as f: spec = convert_to_openapi(json.load(f)) assert "http://another.api.com" == spec.servers[0].url
def load_spec(spec_source: str, is_http: bool) -> OpenAPISpecification: spec_text: str if is_http: try: response = requests.get(spec_source) spec_text = response.text except RequestException: raise Exception(f"Failed to load {spec_source}") else: with open(spec_source, encoding="utf8") as spec_file: spec_text = spec_file.read() spec = convert_to_openapi((json.loads if spec_source.endswith("json") else yaml.safe_load)(spec_text)) return OpenAPISpecification(spec, spec_source, make_definitions_from_spec(spec))
def log(self, request: Request, response: Response): RequestBuilder.validate(request) ResponseBuilder.validate(response) host = request.host reqres = HttpExchange(request=request, response=response) if host not in self._logs: log_file = os.path.join(self._log_dir, "{}-recordings.jsonl".format(host)) if self._append and os.path.exists(log_file): self._logs[host] = open(log_file, "a") else: self._logs[host] = open(log_file, "w") HttpExchangeWriter(self._logs[host]).write(reqres) self._logs[host].flush() logger.debug("Logs for %s were updated", host) if self._update_mode: spec_file = os.path.join( self._specs_dir, "{}_{}.json".format(host, self._update_mode.name.lower()), ) if host not in self._specs: if os.path.exists(spec_file) and self._append: with open(spec_file, "r") as f: self._specs[host] = convert_to_openapi(json.load(f)) else: self._specs[host] = BASE_SCHEMA self._specs[host] = update_openapi(self._specs[host], reqres, self._update_mode) with open(spec_file, "w") as f: spec = convert_from_openapi(self._specs[host]) json.dump(spec, f) f.flush() logger.debug("Schema for %s was updated", host)
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_matcher(): _bfoo = { "parameters": [ { "in": "path", "name": "foo", "schema": {"type": "string", "pattern": "^[abc]+$"}, }, ], } bfoo = convert_to_PathItem(_bfoo) oai: OpenAPIObject = convert_to_openapi( { "openapi": "", "info": {"title": "", "version": ""}, "paths": {"/b/{foo}": _bfoo}, } ) assert matches("/a/b", "/a/b", bfoo, "get", oai) assert not matches("/a/", "/a/b", bfoo, "get", oai) assert not matches("/a/b", "/a", bfoo, "get", oai) assert matches("/a/b/c", "/a/{fewfwef}/c", bfoo, "get", oai) assert matches("/b/ccaaca", "/b/{foo}", bfoo, "get", oai) assert not matches("/b/ccaacda", "/b/{foo}", bfoo, "get", oai)
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": "", }, }, }),
assert not matches(["a"], "/a/b", bfoo, "get") assert not matches(["a", "b"], "/a", bfoo, "get") assert matches(["a", "b", "c"], "/a/{fewfwef}/c", bfoo, "get") assert matches(["b", "ccaaca"], "/b/{foo}", bfoo, "get") assert matches(["b", "ccaaca"], "/b/{foo}", bfoo, "get") assert not matches(["a", "b", "c"], "/a/{fewfwef}/c", bfoo, "post") def test_ref_name(): assert "Foo" == ref_name(Reference(_ref="#/components/schemas/Foo", _x=None)) baseO: OpenAPIObject = convert_to_openapi( { "openapi": "hello", "info": {"title": "", "version": ""}, "servers": [{"url": "https://hello.api.com"}], "paths": {}, } ) # def test_use_if_header(): # assert ( # use_if_header(baseO, convert_to_Parameter({"name": "foo", "in": "query"})) # is None # ) # assert use_if_header( # baseO, convert_to_Parameter({"name": "foo", "in": "header"}) # ) == ("foo", convert_to_Schema({"type": "string"})) # assert use_if_header( # baseO,
def schema(): with open("tests/build/schemas/petstore/index.yaml", "r") as f: oas = convert_to_openapi(safe_load(f.read())) return oas