async def test_client_installation_HTTP_500(httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request("/users/owner/installation").respond_with_data( "This is an 5XX error", status=500 ) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): async with github.AsyncGithubInstallationClient( github.get_auth(github_types.GitHubLogin("owner")) ) as client: with pytest.raises(http.HTTPServerSideError) as exc_info: await client.get(httpserver.url_for("/")) # 5 retries assert len(httpserver.log) == 5 assert exc_info.value.message == "This is an 5XX error" assert exc_info.value.status_code == 500 assert exc_info.value.response.status_code == 500 assert str(exc_info.value.request.url) == httpserver.url_for( "/users/owner/installation" ) httpserver.check_assertions()
async def test_subscription_on_premise_valid( redis_cache: utils.RedisCache, httpserver: httpserver.HTTPServer, ) -> None: httpserver.expect_request( "/on-premise/subscription/1234").respond_with_json({ "subscription_active": True, "subscription_reason": "azertyuio", "features": [ "private_repository", "large_repository", "priority_queues", "custom_checks", "random_request_reviews", "merge_bot_account", "queue_action", ], }) with mock.patch( "mergify_engine.config.SUBSCRIPTION_BASE_URL", httpserver.url_for("/")[:-1], ): await subscription.SubscriptionDashboardOnPremise.get_subscription( redis_cache, 1234) assert len(httpserver.log) == 1 httpserver.check_assertions()
def test_market_event_forward(_: mock.PropertyMock, httpserver: httpserver.HTTPServer) -> None: with open( os.path.join(os.path.dirname(__file__), "events", "marketplace.json")) as f: data = f.read() headers = { "X-GitHub-Delivery": str(uuid.uuid4()), "X-GitHub-Event": "purchased", "X-Hub-Signature": f"sha1={utils.compute_hmac(data.encode(), config.WEBHOOK_SECRET)}", "User-Agent": "GitHub-Hookshot/044aadd", "Content-Type": "application/json", } httpserver.expect_request("/", method="POST", data=data, headers=headers).respond_with_data("") with mock.patch( "mergify_engine.config.WEBHOOK_MARKETPLACE_FORWARD_URL", httpserver.url_for("/"), ): with testclient.TestClient(root.app) as client: client.post("/marketplace", data=data, headers=headers) httpserver.check_assertions() # type: ignore[no-untyped-call]
async def _do_test_client_installation_token( httpserver: httpserver.HTTPServer, endpoint: str, owner_name: typing.Optional[github_types.GitHubLogin] = None, owner_id: typing.Optional[github_types.GitHubAccountIdType] = None, ) -> None: with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): httpserver.expect_request(endpoint).respond_with_json({ "id": 12345, "target_type": "User", "permissions": { "checks": "write", "contents": "write", "pull_requests": "write", }, "account": { "login": "******", "id": 12345 }, }) httpserver.expect_request( "/app/installations/12345/access_tokens").respond_with_json({ "token": "<app_token>", "expires_at": "2100-12-31T23:59:59Z" }) httpserver.expect_request("/", headers={ "Authorization": "token <installation-token>" }).respond_with_json({"work": True}, status=200) async with github.AsyncGithubInstallationClient( github.get_auth(owner_name=owner_name, owner_id=owner_id)) as client: ret = await client.get(httpserver.url_for("/")) assert ret.json()["work"] assert client.auth.owner == "testing" assert client.auth.owner_id == 12345 assert len(httpserver.log) == 3 httpserver.check_assertions()
async def test_client_401_raise_ratelimit( httpserver: httpserver.HTTPServer) -> None: owner = github_types.GitHubLogin("owner") repo = "repo" httpserver.expect_request("/users/owner/installation").respond_with_json({ "id": 12345, "target_type": "User", "permissions": { "checks": "write", "contents": "write", "pull_requests": "write", }, "account": { "login": "******", "id": 12345 }, }) httpserver.expect_request( "/app/installations/12345/access_tokens").respond_with_json( { "token": "<token>", "expires_at": "2100-12-31T23:59:59Z" }, headers={ "X-RateLimit-Remaining": 5000, "X-RateLimit-Reset": 1234567890 }, ) httpserver.expect_oneshot_request( "/repos/owner/repo/pull/1").respond_with_json( {"message": "quota !"}, status=403, headers={ "X-RateLimit-Remaining": 0, "X-RateLimit-Reset": 1234567890 }, ) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): async with github.aget_client(owner) as client: with pytest.raises(exceptions.RateLimited): await client.item(f"/repos/{owner}/{repo}/pull/1") httpserver.check_assertions()
async def test_client_HTTP_400(httpserver: httpserver.HTTPServer) -> None: httpserver.expect_oneshot_request("/").respond_with_json( {"message": "This is an 4XX error"}, status=400) async with http.AsyncClient() as client: with pytest.raises(http.HTTPClientSideError) as exc_info: await client.get(httpserver.url_for("/")) assert exc_info.value.message == "This is an 4XX error" assert exc_info.value.status_code == 400 assert exc_info.value.response.status_code == 400 assert str(exc_info.value.request.url) == httpserver.url_for("/") httpserver.check_assertions()
async def test_client_abuse_403_no_header( httpserver: httpserver.HTTPServer) -> None: abuse_message = ("You have triggered an abuse detection mechanism. " "Please wait a few minutes before you try again.") httpserver.expect_request("/users/owner/installation").respond_with_json({ "id": 12345, "target_type": "User", "permissions": { "checks": "write", "contents": "write", "pull_requests": "write", }, "account": { "login": "******", "id": 12345 }, }) httpserver.expect_request( "/app/installations/12345/access_tokens").respond_with_json({ "token": "<token>", "expires_at": "2100-12-31T23:59:59Z" }) httpserver.expect_oneshot_request("/").respond_with_json( {"message": abuse_message}, status=403, ) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): async with github.AsyncGithubInstallationClient( github.get_auth(github_types.GitHubLogin("owner"))) as client: with pytest.raises(http.HTTPClientSideError) as exc_info: await client.get(httpserver.url_for("/")) assert exc_info.value.message == abuse_message assert exc_info.value.status_code == 403 assert exc_info.value.response.status_code == 403 assert str(exc_info.value.request.url) == httpserver.url_for("/") assert len(httpserver.log) == 3 httpserver.check_assertions()
async def test_send_seats(httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request( "/on-premise/report", method="POST", json={"seats": 5, "write_users": 5, "active_users": 2, "engine_version": "dev"}, ).respond_with_data("Accepted", status=201) with mock.patch( "mergify_engine.config.SUBSCRIPTION_BASE_URL", httpserver.url_for("/")[:-1], ): await count_seats.send_seats(count_seats.SeatsCountResultT(5, 2)) assert len(httpserver.log) == 1 httpserver.check_assertions() # type: ignore [no-untyped-call]
async def test_client_installation_HTTP_404( httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request("/users/owner/installation").respond_with_json( {"message": "Repository not found"}, status=404) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): async with github.AsyncGithubInstallationClient( github.get_auth(github_types.GitHubLogin("owner"))) as client: with pytest.raises(exceptions.MergifyNotInstalled): await client.get(httpserver.url_for("/")) assert len(httpserver.log) == 1 httpserver.check_assertions()
async def test_client_HTTP_500(httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request("/").respond_with_data("This is an 5XX error", status=500) async with http.AsyncClient() as client: with pytest.raises(http.HTTPServerSideError) as exc_info: await client.get(httpserver.url_for("/")) # 5 retries assert len(httpserver.log) == 5 assert exc_info.value.message == "This is an 5XX error" assert exc_info.value.status_code == 500 assert exc_info.value.response.status_code == 500 assert str(exc_info.value.request.url) == httpserver.url_for("/") httpserver.check_assertions()
def test_client_temporary_HTTP_500(httpserver: httpserver.HTTPServer) -> None: httpserver.expect_oneshot_request("/").respond_with_data( "This is an 5XX error", status=500) httpserver.expect_oneshot_request("/").respond_with_data( "This is an 5XX error", status=500) httpserver.expect_oneshot_request("/").respond_with_data( "This is an 5XX error", status=500) httpserver.expect_request("/").respond_with_data("It works now !", status=200) with http.Client() as client: client.get(httpserver.url_for("/")) # 4 retries assert len(httpserver.log) == 4 httpserver.check_assertions()
async def test_subscription_on_premise_invalid_sub( redis_cache: utils.RedisCache, httpserver: httpserver.HTTPServer, ) -> None: httpserver.expect_request( "/on-premise/subscription/1234").respond_with_json( {"message": "error"}, status=403) with mock.patch( "mergify_engine.config.SUBSCRIPTION_BASE_URL", httpserver.url_for("/")[:-1], ): with pytest.raises(exceptions.MergifyNotInstalled): await subscription.SubscriptionDashboardOnPremise.get_subscription( redis_cache, 1234) assert len(httpserver.log) == 1 httpserver.check_assertions()
def test_client_installation_token(httpserver: httpserver.HTTPServer) -> None: with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): httpserver.expect_request( "/users/owner/installation").respond_with_json({ "id": 12345, "target_type": "User", "permissions": { "checks": "write", "contents": "write", "pull_requests": "write", }, "account": { "login": "******", "id": 12345 }, }) httpserver.expect_request( "/app/installations/12345/access_tokens").respond_with_json({ "token": "<app_token>", "expires_at": "2100-12-31T23:59:59Z" }) httpserver.expect_request("/", headers={ "Authorization": "token <installation-token>" }).respond_with_json({"work": True}, status=200) with github.GithubInstallationClient( github.get_auth("owner")) as client: ret = client.get(httpserver.url_for("/")) assert ret.json()["work"] assert len(httpserver.log) == 3 httpserver.check_assertions()
async def test_client_access_token_HTTP_500( httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request("/users/owner/installation").respond_with_json({ "id": 12345, "target_type": "User", "permissions": { "checks": "write", "contents": "write", "pull_requests": "write", }, "account": { "login": "******", "id": 12345 }, }) httpserver.expect_request( "/app/installations/12345/access_tokens").respond_with_data( "This is an 5XX error", status=500) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): async with github.AsyncGithubInstallationClient( github.get_auth(github_types.GitHubLogin("owner"))) as client: with pytest.raises(http.HTTPServerSideError) as exc_info: await client.get(httpserver.url_for("/")) # installation request + 5 retries assert len(httpserver.log) == 6 assert exc_info.value.message == "This is an 5XX error" assert exc_info.value.status_code == 500 assert exc_info.value.response.status_code == 500 assert str(exc_info.value.request.url) == httpserver.url_for( "/app/installations/12345/access_tokens") httpserver.check_assertions()
async def _do_test_client_retry_429( httpserver: httpserver.HTTPServer, retry_after: str, expected_seconds: int ) -> None: records = [] def record_date(_): records.append(datetime.datetime.utcnow()) return Response("It works now !", 200) httpserver.expect_oneshot_request("/").respond_with_data( "This is an 429 error", status=429, headers={"Retry-After": retry_after} ) httpserver.expect_request("/").respond_with_handler(record_date) async with http.AsyncClient() as client: now = datetime.datetime.utcnow() await client.get(httpserver.url_for("/")) assert len(httpserver.log) == 2 elapsed_seconds = (records[0] - now).total_seconds() assert expected_seconds - 1 < elapsed_seconds <= expected_seconds + 1 httpserver.check_assertions()
def test_client_installation_HTTP_301( httpserver: httpserver.HTTPServer) -> None: httpserver.expect_request("/users/owner/installation").respond_with_data( status=301, headers={ "Location": httpserver.url_for("/repositories/12345/installation") }, ) httpserver.expect_request( "/repositories/12345/installation").respond_with_json( {"message": "Repository not found"}, status=404) with mock.patch( "mergify_engine.config.GITHUB_API_URL", httpserver.url_for("/")[:-1], ): with github.GithubInstallationClient( github.get_auth("owner")) as client: with pytest.raises(exceptions.MergifyNotInstalled): client.get(httpserver.url_for("/")) assert len(httpserver.log) == 2 httpserver.check_assertions()