async def test_external_pass_through(client): # pragma: nocover with respx.mock: # Mock pass-through call url = "https://httpbin.org/post" route = respx.post(url).respond(content=b"").pass_through() # Mock a non-matching callback pattern pre-reading request data def callback(req): req.read() # TODO: Make this not needed, might affect pass-through assert req.content == b'{"foo": "bar"}' return None respx.add(callback) # Make external pass-through call assert route.call_count == 0 response = await client.post(url, json={"foo": "bar"}) assert response.content is not None assert len(response.content) > 0 assert "Content-Length" in response.headers assert int(response.headers["Content-Length"]) > 0 assert response.json()["json"] == {"foo": "bar"} assert respx.calls.last.request.url == url assert respx.calls.last.response is None # TODO: Routed and recorded twice; AsyncConnectionPool + AsyncHTTPConnection assert route.call_count == 2 assert respx.calls.call_count == 2
async def test_external_pass_through(client): # pragma: nocover with respx.mock: # Mock pass-through call url = "https://httpbin.org/post" respx.get(url, content=b"", pass_through=True) # Mock a non-matching callback pattern pre-reading request data def callback(req, res): req.read() # TODO: Make this not needed, might affect pass-through assert req.content == b'{"foo": "bar"}' return None respx.add(callback) # Make external pass-through call response = await client.post(url, json={"foo": "bar"}) assert response.content is not None assert len(response.content) > 0 assert "Content-Length" in response.headers assert int(response.headers["Content-Length"]) > 0 assert response.json()["json"] == {"foo": "bar"} _, resp = respx.calls[-1] await resp.aread() # Read async pass-through response assert resp.content == b"", "Should be 0, stream already read by real Response!" assert "Content-Length" in resp.headers assert int(resp.headers["Content-Length"]) > 0
async def test_start_stop(client): url = "https://foo.bar/" request = respx.add("GET", url, status_code=202) assert respx.stats.call_count == 0 try: respx.start() response = await client.get(url) assert request.called is True assert response.status_code == 202 assert response.text == "" assert respx.stats.call_count == 1 respx.stop(clear=False, reset=False) assert len(respx.mock.patterns) == 1 assert respx.stats.call_count == 1 assert request.called is True respx.reset() assert len(respx.mock.patterns) == 1 assert respx.stats.call_count == 0 assert request.called is False respx.clear() assert len(respx.mock.patterns) == 0 except Exception: # pragma: nocover respx.stop() # Cleanup global state on error, to not affect other tests raise
def test_add(): with respx.mock: route = Route(method="GET", url="https://foo.bar/") respx.add(route, name="foobar") response = httpx.get("https://foo.bar/") assert response.status_code == 200 assert respx.routes["foobar"].called with pytest.raises(TypeError): respx.add(route, status_code=418) # pragma: nocover with pytest.raises(ValueError): respx.add("GET") # pragma: nocover with pytest.raises(NotImplementedError): route.name = "spam" with pytest.raises(NotImplementedError): route.pattern &= M(params={"foo": "bar"})
def test_restore(rt, app, client, mstorage): # pylint: disable=too-many-statements # Create fake backup (not pretty but sufficient?) storage = mstorage.get_storage(rt.storage_name) storage.upload_json(BACKUP_NAME, BACKUP_MANIFEST) nodes = app.state.coordinator_config.nodes with respx.mock: for i, node in enumerate(nodes): respx.post(f"{node.url}/unlock?locker=x&ttl=0", content={"locked": False}) # Failure point 1: Lock fails respx.post(f"{node.url}/lock?locker=x&ttl=60", content={"locked": rt.fail_at != 1}) if i == 0: # Failure point 2: download call fails url = f"{node.url}/download" def match_download(request, response, *, _url=url): if request.method != "POST" or _url != str(request.url): return None if rt.fail_at == 2: return None if json.loads( request.read())["storage"] != storage.storage_name: return None if json.loads(request.read())["root_globs"] != ["*"]: return None return response result_url = f"{node.url}/download/result" respx.add(match_download, content={ "op_id": 42, "status_url": result_url }) # Failure point 3: download result call fails respx.get(result_url, content={ "progress": { "handled": 10, "failed": 0, "total": 10, "final": True }, }, status_code=200 if rt.fail_at != 3 else 500) else: url = f"{node.url}/clear" def match_clear(request, response, *, _url=url): if request.method != "POST" or _url != str(request.url): return None if rt.fail_at == 4: return None if json.loads(request.read())["root_globs"] != ["*"]: return None return response result_url = f"{node.url}/clear/result" respx.add(match_clear, content={ "op_id": 42, "status_url": result_url }) # Failure point 5: clear result call fails respx.get(result_url, content={ "progress": { "final": True }, }, status_code=200 if rt.fail_at != 5 else 500) req = {} if rt.storage_name: req["storage"] = rt.storage_name if rt.partial: req["partial_restore_nodes"] = [{ "node_index": 0, "backup_index": 0 }] response = client.post("/restore", json=req) if rt.fail_at == 1: # Cluster lock failure is immediate assert response.status_code == 409, response.json() assert app.state.coordinator_state.op_info.op_id == 0 return assert response.status_code == 200, response.json() response = client.get(response.json()["status_url"]) assert response.status_code == 200, response.json() if rt.fail_at: assert response.json().get("state") == "fail" assert response.json().get("progress") is not None assert response.json().get("progress")["final"] else: assert response.json().get("state") == "done" assert response.json().get("progress") is not None assert response.json().get("progress")["final"] if rt.fail_at == 5 or rt.fail_at is None: assert response.json().get("progress")["handled"] == 10 assert response.json().get("progress")["failed"] == 0 assert response.json().get("progress")["total"] == 10 else: assert response.json().get("progress")["handled"] == 0 assert response.json().get("progress")["failed"] == 0 assert response.json().get("progress")["total"] == 0 assert app.state.coordinator_state.op_info.op_id == 1
async def test_deprecated_apis(): with respx.mock: url = "https://foo.bar/" # Response kwargs among request kwargs with warnings.catch_warnings(record=True) as w: respx.get(url, status_code=201) respx.get(url, headers={}) respx.get(url, content_type="foo/bar") respx.get(url, content="") respx.get(url, text="") respx.get(url, html="") respx.get(url, json={}) respx.get(url, pass_through=True) assert len(w) == 8 # Add route by http method string with warnings.catch_warnings(record=True) as w: respx.add("GET", url) assert len(w) == 1 # Alias and aliases with warnings.catch_warnings(record=True) as w: request_pattern = respx.get(url, alias="index") name = request_pattern.alias aliased_pattern = respx.mock.aliases["index"] assert aliased_pattern is request_pattern assert name == request_pattern.name assert len(w) == 3 # RequestPattern with warnings.catch_warnings(record=True) as w: callback = lambda req, res: res # pragma: nocover request_pattern = RequestPattern(callback) assert request_pattern.has_side_effect request_pattern = RequestPattern("GET", "https://foo.bar/", pass_through=True) assert request_pattern.is_pass_through assert len(w) == 2 # ResponseTemplate with warnings.catch_warnings(record=True) as w: request = httpx.Request("GET", "https://foo.bar/") callback = lambda request: ResponseTemplate(201) request_pattern = RequestPattern(callback, response=ResponseTemplate(444)) assert request_pattern.resolve(request).status_code == 201 request_pattern = RequestPattern("GET", response=ResponseTemplate(444)) assert request_pattern.resolve(request).status_code == 444 assert len(w) == 5 # Mixing callback and response details with pytest.raises(NotImplementedError): callback = lambda request: ResponseTemplate(201) # pragma: nocover respx.Router().add(callback, status_code=201) # Async callback with pytest.raises(NotImplementedError): async def callback(request): return None # pragma: nocover mock_response = MockResponse(content=callback) request = httpx.Request("GET", "http://foo.bar/") mock_response.as_response(request)