async def test_remuneration_endpoint(client): resp = await client.get("/schema") spec = create_spec(json.loads(resp.body)) resp = await client.post( "/remuneration", body={ "beneficiaire.age": 20, "formation.region": 27, "formation.codes_financeur": [2], }, ) assert resp.status == HTTPStatus.OK assert "remunerations" in json.loads(resp.body) remunerations = json.loads(resp.body)["remunerations"] assert remunerations print(remunerations[0]) assert "remuneration" in remunerations[0] assert "Version" in resp.headers validator = ResponseValidator(spec) request = MockRequest("http://trefle.pole-emploi.fr", "post", "/remuneration") response = MockResponse(resp.body, resp.status.value) result = validator.validate(request, response) result.raise_for_errors()
async def test_simulate_endpoint(client): resp = await client.get("/schema") spec = create_spec(json.loads(resp.body)) resp = await client.post( "/financement", body={ "beneficiaire.solde_cpf": 10, "beneficiaire.remuneration": 1400, "beneficiaire.droit_prive": True, "beneficiaire.contrat": "cdi", "formation.eligible_cpf": True, "formation.heures": 100, "beneficiaire.entreprise.commune": "2A004", "beneficiaire.entreprise.idcc": 2706, }, ) assert resp.status == HTTPStatus.OK assert "financements" in json.loads(resp.body) financements = json.loads(resp.body)["financements"] print(financements[0]) assert financements assert financements[0].get("eligible") assert "Version" in resp.headers validator = ResponseValidator(spec) request = MockRequest("http://trefle.pole-emploi.fr", "post", "/financement") response = MockResponse(resp.body, resp.status.value) result = validator.validate(request, response) result.raise_for_errors()
class OpenApiSpecManager(SharedExtension): _loaded = Event() def setup(self): log.info(' ### OpenApiSpecManager.setup') super().setup() def load_spec(self, spec_file): log.debug('%s.load_spec: %s' % (self.__class__.__name__, spec_file)) # TODO: supporting loading from url instead of just file # TODO: How to handle/interpret/respect spec.servers[].url's? # TODO: Or should this be generated/injected into the spec_dict on startup? #spec_file = '/home/sar/vcs/nameko-openapi/petstore.yaml' spec_dict = yaml.safe_load(open(spec_file)) self.spec = openapi_core.create_spec(spec_dict) self.request_validator = RequestValidator(self.spec) self.response_validator = ResponseValidator(self.spec) self._loaded.send(self.spec) def wait_for_spec(self): """Allow other extensions to wait until the spec is loaded.""" return self._loaded.wait() def get_operation_by_id(self, operation_id): self.wait_for_spec() for path_name, path in six.iteritems(self.spec.paths): for http_method, operation in six.iteritems(path.operations): if operation.operation_id == operation_id: return operation def validate_request(self, request, raise_for_errors=True): result = self.request_validator.validate(request) if raise_for_errors: result.raise_for_errors() return result def validate_response(self, response, openapi_request, raise_for_errors=True): result = self.response_validator.validate(openapi_request, response) if raise_for_errors: result.raise_for_errors() return result
def test_healthz(client): """Test the /healthz endpoint.""" path = '/v1/healthz' rv = client.get(path) # Validate request and response against OpenAPI spec with app.test_request_context(path): with open(app.config['OPENAPI_SPEC']) as stream: spec = create_spec(safe_load(stream)) openapi_response = FlaskOpenAPIResponse(rv) openapi_request = FlaskOpenAPIRequest(request) validator = ResponseValidator(spec) result = validator.validate(openapi_request, openapi_response) result.raise_for_errors() assert rv.content_type == "text/plain" assert rv.status_code == 200 assert b'OK' in rv.data
async def test_simulate_endpoint_with_invalid_data(client): resp = await client.get("/schema") spec = create_spec(json.loads(resp.body)) resp = await client.post( "/financement", body={ "beneficiaire.remuneration": "1400", "beneficiaire.droit_prive": "invalide", "beneficiaire.entreprise.idcc": 2706, }, ) assert resp.status == HTTPStatus.UNPROCESSABLE_ENTITY assert "application/json" in resp.headers["Content-Type"] validator = ResponseValidator(spec) request = MockRequest("http://trefle.pole-emploi.fr", "post", "/financement") response = MockResponse(resp.body, resp.status.value) result = validator.validate(request, response) result.raise_for_errors()
class Client: def __init__( self, spec: Union[Spec, dict], *, server_url: Optional[str] = None, client: Union[ModuleType, Requestable] = httpx, request_class: Type[ClientOpenAPIRequest] = ClientOpenAPIRequest, response_factory: Callable[[Any], OpenAPIResponse] = ClientOpenAPIResponse, headers: Optional[dict] = None, ): if not isinstance(spec, Spec): spec = create_spec(spec) self.spec = spec self.client = client self.request_class = request_class self.response_factory = response_factory self.common_headers = headers or {} if server_url is None: server_url = self.spec.servers[0].url else: server_url = server_url.rstrip("/") for server in self.spec.servers: if server_url == server.url: break else: self.spec.servers.append(Server(server_url)) self.server_url = server_url self.validator = ResponseValidator(self.spec) for path_spec in spec.paths.values(): for op_spec in path_spec.operations.values(): setattr( self, snakecase(op_spec.operation_id), self._get_operation(op_spec).__get__(self), ) @staticmethod def _get_operation(op_spec): # TODO: extract args and kwargs from operation parameters def operation( self, *args, body_: Optional[Union[dict, list]] = None, headers_: Optional[dict] = None, **kwargs, ): request_headers = self.common_headers.copy() request_headers.update(headers_ or {}) request = self.request_class(self.server_url, op_spec) request.prepare(*args, body_=body_, headers_=request_headers, **kwargs) request_params = { "method": request.method, "url": request.url, "headers": request.headers, } if request.body: request_params["json" if "json" in request.mimetype else "data"] = request.body api_response = self.client.request(**request_params) api_response.raise_for_status() response = self.response_factory(api_response) self.validator.validate(request, response).raise_for_errors() return response operation.__doc__ = op_spec.summary or op_spec.operation_id if op_spec.description: operation.__doc__ += f"\n\n{op_spec.description}" return operation @classmethod def from_file(cls, path: Union[Path, str], **kwargs): """Creates an instance of the class by loading the spec from a local file.""" spec = get_spec_from_file(path) return cls(spec, **kwargs)