chore: package updates and fix ci

This commit is contained in:
Andrew Herrington
2024-05-05 13:39:25 -05:00
parent 4ca01eaf0c
commit 778932a2f8
23 changed files with 749 additions and 956 deletions

View File

@@ -16,7 +16,7 @@ updates:
directory: "/docs" directory: "/docs"
schedule: schedule:
interval: daily interval: daily
commit-message: commit-message:
prefix: docs prefix: docs
- package-ecosystem: pip - package-ecosystem: pip
directory: "/" directory: "/"
@@ -24,4 +24,3 @@ updates:
interval: daily interval: daily
commit-message: commit-message:
prefix: deps prefix: deps

View File

@@ -1,6 +1,6 @@
pip==23.1.2 pip==24.0.0
nox==2023.4.22 nox==2024.4.15
nox-poetry==1.0.2 nox-poetry==1.0.3
poetry==1.5.1 poetry==1.8.2
virtualenv==20.23.1 virtualenv==20.26.1
toml==0.10.2 toml==0.10.2

View File

@@ -13,18 +13,11 @@ jobs:
include: include:
- { python: "3.10", os: "ubuntu-latest", session: "pre-commit" } - { python: "3.10", os: "ubuntu-latest", session: "pre-commit" }
- { python: "3.10", os: "ubuntu-latest", session: "safety" } - { python: "3.10", os: "ubuntu-latest", session: "safety" }
# - { python: "3.10", os: "ubuntu-latest", session: "mypy" }
# - { python: "3.9", os: "ubuntu-latest", session: "mypy" }
# - { python: "3.8", os: "ubuntu-latest", session: "mypy" }
# - { python: "3.7", os: "ubuntu-latest", session: "mypy" }
- { python: "3.10", os: "ubuntu-latest", session: "tests" } - { python: "3.10", os: "ubuntu-latest", session: "tests" }
- { python: "3.11", os: "ubuntu-latest", session: "tests" } - { python: "3.11", os: "ubuntu-latest", session: "tests" }
- { python: "3.9", os: "ubuntu-latest", session: "tests" } - { python: "3.9", os: "ubuntu-latest", session: "tests" }
- { python: "3.8", os: "ubuntu-latest", session: "tests" } - { python: "3.8", os: "ubuntu-latest", session: "tests" }
- { python: "3.7", os: "ubuntu-latest", session: "tests" } - { python: "3.7", os: "ubuntu-latest", session: "tests" }
# - { python: "3.10", os: "windows-latest", session: "tests" }
# - { python: "3.10", os: "macos-latest", session: "tests" }
# - { python: "3.10", os: "ubuntu-latest", session: "typeguard" }
- { python: "3.10", os: "ubuntu-latest", session: "xdoctest" } - { python: "3.10", os: "ubuntu-latest", session: "xdoctest" }
- { python: "3.10", os: "ubuntu-latest", session: "docs-build" } - { python: "3.10", os: "ubuntu-latest", session: "docs-build" }
@@ -80,7 +73,7 @@ jobs:
payload = sys.version.encode() + sys.executable.encode() payload = sys.version.encode() + sys.executable.encode()
digest = hashlib.sha256(payload).hexdigest() digest = hashlib.sha256(payload).hexdigest()
result = "${{ runner.os }}-{}-{}-pre-commit".format(python, digest[:8]) result = "${{ runner.os }}-{}-{}-pre-commit".format(python, digest[:8])
with open(os.environ['GITHUB_OUTPUT'], 'a') as fh: with open(os.environ['GITHUB_OUTPUT'], 'a') as fh:
fh.write(f"result={result}\n") fh.write(f"result={result}\n")

View File

@@ -1,12 +1,35 @@
exclude: ".*tests\/fixtures.*"
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.3
hooks:
# Run the linter.
- id: ruff
args: [ --fix ]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/rhysd/actionlint
rev: v1.6.27
hooks:
- id: actionlint-docker
name: Actionlint
- repo: local - repo: local
hooks: hooks:
- id: black - id: bandit
name: black name: bandit
entry: black entry: bandit
language: system language: system
types: [python] types: [python]
require_serial: true require_serial: true
args: ["-c", "pyproject.toml"]
- id: check-added-large-files - id: check-added-large-files
name: Check for added large files name: Check for added large files
entry: check-added-large-files entry: check-added-large-files
@@ -27,38 +50,16 @@ repos:
language: system language: system
types: [text] types: [text]
stages: [commit, push, manual] stages: [commit, push, manual]
- id: flake8
name: flake8
entry: flake8
language: system
types: [python]
exclude: "^(test/*|examples/*|noxfile.py)"
require_serial: true
args: ["--config=.flake8"]
- id: pyupgrade - id: pyupgrade
name: pyupgrade name: pyupgrade
description: Automatically upgrade syntax for newer versions. description: Automatically upgrade syntax for newer versions.
entry: pyupgrade entry: pyupgrade
language: system language: system
types: [python] types: [python]
args: [--py37-plus] args: [--py38-plus]
- id: reorder-python-imports
name: Reorder python imports
entry: reorder-python-imports
language: system
types: [python]
args: [--application-directories=src]
- id: trailing-whitespace - id: trailing-whitespace
name: Trim Trailing Whitespace name: Trim Trailing Whitespace
entry: trailing-whitespace-fixer entry: trailing-whitespace-fixer
language: system language: system
types: [text] types: [text]
stages: [commit, push, manual] stages: [commit, push, manual]
- repo: https://github.com/pre-commit/mirrors-prettier
rev: v2.7.1
hooks:
- id: prettier
- repo: https://github.com/rhysd/actionlint
rev: v1.6.15
hooks:
- id: actionlint-docker

View File

@@ -1,4 +1,5 @@
"""Sphinx configuration.""" """Sphinx configuration."""
from datetime import datetime from datetime import datetime

View File

@@ -1,4 +1,5 @@
"""Nox sessions.""" """Nox sessions."""
import os import os
import shlex import shlex
import shutil import shutil
@@ -23,28 +24,17 @@ except ImportError:
package = "healthchecks_io" package = "healthchecks_io"
python_versions = ["3.10", "3.11", "3.9", "3.8", "3.7"] python_versions = ["3.10", "3.11", "3.9", "3.8"]
nox.needs_version = ">= 2021.6.6" nox.needs_version = ">= 2021.6.6"
nox.options.sessions = ( nox.options.sessions = (
"pre-commit", "pre-commit",
"bandit",
"safety", "safety",
"mypy", # "mypy",
"tests", "tests",
# "typeguard",
"xdoctest", "xdoctest",
"docs-build", "docs-build",
) )
mypy_type_packages = ("types-croniter", "types-pytz")
test_requirements = (
"coverage[toml]",
"pytest",
"pygments",
"respx",
"pytest-asyncio",
"pytest-lazy-fixture",
)
mypy_type_packages = ()
pyproject = toml.load("pyproject.toml") pyproject = toml.load("pyproject.toml")
test_requirements = pyproject["tool"]["poetry"]["group"]["dev"]["dependencies"].keys() test_requirements = pyproject["tool"]["poetry"]["group"]["dev"]["dependencies"].keys()
@@ -118,20 +108,7 @@ def activate_virtualenv_in_precommit_hooks(session: Session) -> None:
def precommit(session: Session) -> None: def precommit(session: Session) -> None:
"""Lint using pre-commit.""" """Lint using pre-commit."""
args = session.posargs or ["run", "--all-files", "--show-diff-on-failure"] args = session.posargs or ["run", "--all-files", "--show-diff-on-failure"]
session.install( session.install(*test_requirements)
"black",
"darglint",
"flake8",
"flake8-bandit",
"flake8-bugbear",
"flake8-docstrings",
"flake8-rst-docstrings",
"pep8-naming",
"pre-commit",
"pre-commit-hooks",
"pyupgrade",
"reorder-python-imports",
)
session.run("pre-commit", *args) session.run("pre-commit", *args)
if args and args[0] == "install": if args and args[0] == "install":
activate_virtualenv_in_precommit_hooks(session) activate_virtualenv_in_precommit_hooks(session)
@@ -153,17 +130,10 @@ def mypy(session: Session) -> None:
args = session.posargs or ["src"] args = session.posargs or ["src"]
session.install(".") session.install(".")
session.install("mypy", "pytest") session.install("mypy", "pytest")
session.install(*mypy_type_packages) session.install(*test_requirements)
session.run("mypy", *args) session.run("mypy", *args)
@session(python=python_versions[0])
def bandit(session: Session) -> None:
"""Run bandit security tests"""
args = session.posargs or ["-r", "./src"]
session.run("bandit", *args)
@session(python=python_versions) @session(python=python_versions)
def tests(session: Session) -> None: def tests(session: Session) -> None:
"""Run the test suite.""" """Run the test suite."""

1340
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ classifiers = [
Changelog = "https://github.com/andrewthetechie/py-healthchecks.io/releases" Changelog = "https://github.com/andrewthetechie/py-healthchecks.io/releases"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.7" python = "^3.8"
pydantic = "^1.9.1" pydantic = "^1.9.1"
httpx = ">=0.23.0,<0.25.0" httpx = ">=0.23.0,<0.25.0"
croniter = "^1.1.0" croniter = "^1.1.0"
@@ -67,6 +67,9 @@ source = ["healthchecks_io"]
show_missing = true show_missing = true
fail_under = 100 fail_under = 100
[tool.bandit]
exclude_dirs = ["tests", "noxfile.py", ".github/scripts", "test_errbot", "dist"]
[tool.mypy] [tool.mypy]
strict = true strict = true
warn_unreachable = true warn_unreachable = true
@@ -84,4 +87,4 @@ addopts = "-n 4 --ignore examples --cov=healthchecks_io --cov-report xml:.covera
[tool.ruff] [tool.ruff]
line-length = 120 line-length = 120
target-version = "py37" target-version = "py38"

View File

@@ -1,4 +1,5 @@
"""Py Healthchecks.Io.""" """Py Healthchecks.Io."""
# set by poetry-dynamic-versioning # set by poetry-dynamic-versioning
__version__ = "0.4.0" # noqa: E402 __version__ = "0.4.0" # noqa: E402

View File

@@ -1,4 +1,5 @@
"""healthchecks_io clients.""" """healthchecks_io clients."""
from .async_client import AsyncClient # noqa: F401 from .async_client import AsyncClient # noqa: F401
from .check_trap import CheckTrap # noqa: F401 from .check_trap import CheckTrap # noqa: F401
from .sync_client import Client # noqa: F401 from .sync_client import Client # noqa: F401

View File

@@ -57,9 +57,7 @@ class AbstractClient(ABC):
"""Finalizer method is called by weakref.finalize when the object is dereferenced to do cleanup of clients.""" """Finalizer method is called by weakref.finalize when the object is dereferenced to do cleanup of clients."""
pass pass
def _get_api_request_url( def _get_api_request_url(self, path: str, params: Optional[Dict[str, Any]] = None) -> str:
self, path: str, params: Optional[Dict[str, Any]] = None
) -> str:
"""Get a full request url for the healthchecks api. """Get a full request url for the healthchecks api.
Args: Args:
@@ -165,9 +163,7 @@ class AbstractClient(ABC):
raise CheckNotFoundError(f"CHeck not found at {response.request.url}") raise CheckNotFoundError(f"CHeck not found at {response.request.url}")
if response.status_code == 400: if response.status_code == 400:
raise BadAPIRequestError( raise BadAPIRequestError(f"Bad request when requesting {response.request.url}. {response.text}")
f"Bad request when requesting {response.request.url}. {response.text}"
)
return response return response
@@ -208,21 +204,15 @@ class AbstractClient(ABC):
raise HCAPIRateLimitError(f"Rate limited on {response.request.url}") raise HCAPIRateLimitError(f"Rate limited on {response.request.url}")
if response.status_code == 400: if response.status_code == 400:
raise BadAPIRequestError( raise BadAPIRequestError(f"Bad request when requesting {response.request.url}. {response.text}")
f"Bad request when requesting {response.request.url}. {response.text}"
)
if response.status_code == 409: if response.status_code == 409:
raise NonUniqueSlugError( raise NonUniqueSlugError(f"Bad request, slug conflict {response.request.url}. {response.text}")
f"Bad request, slug conflict {response.request.url}. {response.text}"
)
return response return response
@staticmethod @staticmethod
def _add_url_params( def _add_url_params(url: str, params: Dict[str, Union[str, int, bool]], replace: bool = True) -> str:
url: str, params: Dict[str, Union[str, int, bool]], replace: bool = True
) -> str:
"""Add GET params to provided URL being aware of existing. """Add GET params to provided URL being aware of existing.
:param url: string of target URL :param url: string of target URL
@@ -255,12 +245,7 @@ class AbstractClient(ABC):
# get all the duplicated keys from params and urlencode them, we'll concat this to the params string later # get all the duplicated keys from params and urlencode them, we'll concat this to the params string later
duplicated_params = [x for x in params if x in parsed_get_args] duplicated_params = [x for x in params if x in parsed_get_args]
# get all the args that aren't duplicated and add them to parsed_get_args # get all the args that aren't duplicated and add them to parsed_get_args
parsed_get_args.update( parsed_get_args.update({key: parsed_params[key] for key in [x for x in params if x not in parsed_get_args]})
{
key: parsed_params[key]
for key in [x for x in params if x not in parsed_get_args]
}
)
# if we have any duplicated parameters, urlencode them, we append them later # if we have any duplicated parameters, urlencode them, we append them later
extra_parameters = ( extra_parameters = (
f"&{urlencode({key: params[key] for key in duplicated_params}, doseq=True)}" f"&{urlencode({key: params[key] for key in duplicated_params}, doseq=True)}"

View File

@@ -1,4 +1,5 @@
"""An async healthchecks.io client.""" """An async healthchecks.io client."""
import asyncio import asyncio
from types import TracebackType from types import TracebackType
from typing import Dict from typing import Dict

View File

@@ -1,4 +1,5 @@
"""CheckTrap is a context manager to wrap around python code to communicate results to a Healthchecks check.""" """CheckTrap is a context manager to wrap around python code to communicate results to a Healthchecks check."""
from types import TracebackType from types import TracebackType
from typing import List from typing import List
from typing import Optional from typing import Optional
@@ -68,9 +69,7 @@ class CheckTrap:
CheckTrap: self CheckTrap: self
""" """
if isinstance(self.client, AsyncClient): if isinstance(self.client, AsyncClient):
raise WrongClientError( raise WrongClientError("You passed an AsyncClient, use this as an async context manager")
"You passed an AsyncClient, use this as an async context manager"
)
result = self.client.start_ping(uuid=self.uuid, slug=self.slug) result = self.client.start_ping(uuid=self.uuid, slug=self.slug)
if not result[0]: if not result[0]:
raise PingFailedError(result[1]) raise PingFailedError(result[1])
@@ -96,9 +95,7 @@ class CheckTrap:
Optional[bool]: self.suppress_exceptions, if true will not raise any exceptions Optional[bool]: self.suppress_exceptions, if true will not raise any exceptions
""" """
if exc_type is None: if exc_type is None:
self.client.success_ping( self.client.success_ping(self.uuid, self.slug, data="\n".join(self.log_lines))
self.uuid, self.slug, data="\n".join(self.log_lines)
)
else: else:
self.add_log(str(exc)) self.add_log(str(exc))
self.add_log(str(traceback)) self.add_log(str(traceback))
@@ -125,9 +122,7 @@ class CheckTrap:
CheckTrap: self CheckTrap: self
""" """
if isinstance(self.client, Client): if isinstance(self.client, Client):
raise WrongClientError( raise WrongClientError("You passed a sync Client, use this as a regular context manager")
"You passed a sync Client, use this as a regular context manager"
)
result = await self.client.start_ping(self.uuid, self.slug) result = await self.client.start_ping(self.uuid, self.slug)
if not result[0]: if not result[0]:
raise PingFailedError(result[1]) raise PingFailedError(result[1])

View File

@@ -1,4 +1,5 @@
"""An async healthchecks.io client.""" """An async healthchecks.io client."""
from types import TracebackType from types import TracebackType
from typing import Dict from typing import Dict
from typing import List from typing import List

View File

@@ -1,4 +1,5 @@
"""Schemas for healthchecks_io.""" """Schemas for healthchecks_io."""
from .badges import Badges from .badges import Badges
from .checks import Check from .checks import Check
from .checks import CheckCreate from .checks import CheckCreate

View File

@@ -2,6 +2,7 @@
https://healthchecks.io/docs/api/ https://healthchecks.io/docs/api/
""" """
from typing import Dict from typing import Dict
from pydantic import BaseModel from pydantic import BaseModel

View File

@@ -2,6 +2,7 @@
https://healthchecks.io/docs/api/ https://healthchecks.io/docs/api/
""" """
from datetime import datetime from datetime import datetime
from pathlib import PurePath from pathlib import PurePath
from typing import Any from typing import Any
@@ -88,8 +89,7 @@ class CheckCreate(BaseModel):
) )
tz: Optional[str] = Field( tz: Optional[str] = Field(
"UTC", "UTC",
description="Server's timezone. This setting only has an effect " description="Server's timezone. This setting only has an effect " "in combination with the schedule parameter.",
"in combination with the schedule parameter.",
) )
manual_resume: Optional[bool] = Field( manual_resume: Optional[bool] = Field(
False, False,
@@ -184,8 +184,7 @@ class CheckUpdate(CheckCreate):
) )
tz: Optional[str] = Field( tz: Optional[str] = Field(
None, None,
description="Server's timezone. This setting only has an effect " description="Server's timezone. This setting only has an effect " "in combination with the schedule parameter.",
"in combination with the schedule parameter.",
) )
manual_resume: Optional[bool] = Field( manual_resume: Optional[bool] = Field(
None, None,

View File

@@ -2,6 +2,7 @@
https://healthchecks.io/docs/api/ https://healthchecks.io/docs/api/
""" """
from typing import Dict from typing import Dict
from pydantic import BaseModel from pydantic import BaseModel

View File

@@ -13,10 +13,7 @@ from healthchecks_io import NonUniqueSlugError
def test_abstract_add_url_params(test_abstract_client): def test_abstract_add_url_params(test_abstract_client):
url = test_abstract_client._add_url_params("http://test.com/?test=test", {"test": "test2"})
url = test_abstract_client._add_url_params(
"http://test.com/?test=test", {"test": "test2"}
)
assert url == "http://test.com/?test=test2" assert url == "http://test.com/?test=test2"

View File

@@ -15,9 +15,7 @@ from healthchecks_io.client.exceptions import HCAPIError
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_acreate_check_200_context_manager( async def test_acreate_check_200_context_manager(fake_check_api_result, respx_mock, test_async_client):
fake_check_api_result, respx_mock, test_async_client
):
checks_url = urljoin(test_async_client._api_url, "checks/") checks_url = urljoin(test_async_client._api_url, "checks/")
respx_mock.post(checks_url).mock( respx_mock.post(checks_url).mock(
return_value=Response( return_value=Response(
@@ -43,9 +41,7 @@ async def test_acreate_check_200_context_manager(
) )
) )
async with test_async_client as test_client: async with test_async_client as test_client:
check = await test_client.create_check( check = await test_client.create_check(CheckCreate(name="test", tags="test", desc="test"))
CheckCreate(name="test", tags="test", desc="test")
)
assert check.name == "Backups" assert check.name == "Backups"
@@ -76,9 +72,7 @@ async def test_acreate_check_200(fake_check_api_result, respx_mock, test_async_c
}, },
) )
) )
check = await test_async_client.create_check( check = await test_async_client.create_check(CheckCreate(name="test", tags="test", desc="test"))
CheckCreate(name="test", tags="test", desc="test")
)
assert check.name == "Backups" assert check.name == "Backups"
@@ -109,9 +103,7 @@ async def test_aupdate_check_200(fake_check_api_result, respx_mock, test_async_c
}, },
) )
) )
check = await test_async_client.update_check( check = await test_async_client.update_check("test", CheckUpdate(name="test", desc="test"))
"test", CheckUpdate(name="test", desc="test")
)
assert check.name == "Backups" assert check.name == "Backups"
@@ -120,9 +112,7 @@ async def test_aupdate_check_200(fake_check_api_result, respx_mock, test_async_c
async def test_aget_checks_200(fake_check_api_result, respx_mock, test_async_client): async def test_aget_checks_200(fake_check_api_result, respx_mock, test_async_client):
assert test_async_client._client is not None assert test_async_client._client is not None
checks_url = urljoin(test_async_client._api_url, "checks/") checks_url = urljoin(test_async_client._api_url, "checks/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"checks": [fake_check_api_result]}))
return_value=Response(status_code=200, json={"checks": [fake_check_api_result]})
)
checks = await test_async_client.get_checks() checks = await test_async_client.get_checks()
assert len(checks) == 1 assert len(checks) == 1
assert checks[0].name == fake_check_api_result["name"] assert checks[0].name == fake_check_api_result["name"]
@@ -132,13 +122,9 @@ async def test_aget_checks_200(fake_check_api_result, respx_mock, test_async_cli
@pytest.mark.respx @pytest.mark.respx
async def test_aget_checks_pass_in_client(fake_check_api_result, respx_mock): async def test_aget_checks_pass_in_client(fake_check_api_result, respx_mock):
httpx_client = HTTPXAsyncClient() httpx_client = HTTPXAsyncClient()
test_async_client = AsyncClient( test_async_client = AsyncClient(api_key="test", api_url="http://localhost/api/", client=httpx_client)
api_key="test", api_url="http://localhost/api/", client=httpx_client
)
checks_url = urljoin(test_async_client._api_url, "checks/") checks_url = urljoin(test_async_client._api_url, "checks/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"checks": [fake_check_api_result]}))
return_value=Response(status_code=200, json={"checks": [fake_check_api_result]})
)
checks = await test_async_client.get_checks() checks = await test_async_client.get_checks()
assert len(checks) == 1 assert len(checks) == 1
assert checks[0].name == fake_check_api_result["name"] assert checks[0].name == fake_check_api_result["name"]
@@ -146,9 +132,7 @@ async def test_aget_checks_pass_in_client(fake_check_api_result, respx_mock):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_aget_checks_exceptions( async def test_aget_checks_exceptions(fake_check_api_result, respx_mock, test_async_client):
fake_check_api_result, respx_mock, test_async_client
):
checks_url = urljoin(test_async_client._api_url, "checks/") checks_url = urljoin(test_async_client._api_url, "checks/")
# test exceptions # test exceptions
respx_mock.get(checks_url).mock(return_value=Response(status_code=401)) respx_mock.get(checks_url).mock(return_value=Response(status_code=401))
@@ -186,9 +170,7 @@ def test_finalizer_closes(test_async_client):
async def test_aget_check_200(fake_check_api_result, respx_mock, test_async_client): async def test_aget_check_200(fake_check_api_result, respx_mock, test_async_client):
assert test_async_client._client is not None assert test_async_client._client is not None
checks_url = urljoin(test_async_client._api_url, "checks/test") checks_url = urljoin(test_async_client._api_url, "checks/test")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = await test_async_client.get_check(check_id="test") check = await test_async_client.get_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -207,9 +189,7 @@ async def test_acheck_get_404(respx_mock, test_async_client):
@pytest.mark.respx @pytest.mark.respx
async def test_pause_check_200(fake_check_api_result, respx_mock, test_async_client): async def test_pause_check_200(fake_check_api_result, respx_mock, test_async_client):
checks_url = urljoin(test_async_client._api_url, "checks/test/pause") checks_url = urljoin(test_async_client._api_url, "checks/test/pause")
respx_mock.post(checks_url).mock( respx_mock.post(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = await test_async_client.pause_check(check_id="test") check = await test_async_client.pause_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -229,9 +209,7 @@ async def test_acheck_pause_404(respx_mock, test_async_client):
async def test_adelete_check_200(fake_check_api_result, respx_mock, test_async_client): async def test_adelete_check_200(fake_check_api_result, respx_mock, test_async_client):
assert test_async_client._client is not None assert test_async_client._client is not None
checks_url = urljoin(test_async_client._api_url, "checks/test") checks_url = urljoin(test_async_client._api_url, "checks/test")
respx_mock.delete(checks_url).mock( respx_mock.delete(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = await test_async_client.delete_check(check_id="test") check = await test_async_client.delete_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -247,15 +225,9 @@ async def test_adelete_pause404(respx_mock, test_async_client):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_aget_check_pings_200( async def test_aget_check_pings_200(fake_check_pings_api_result, respx_mock, test_async_client):
fake_check_pings_api_result, respx_mock, test_async_client
):
checks_url = urljoin(test_async_client._api_url, "checks/test/pings/") checks_url = urljoin(test_async_client._api_url, "checks/test/pings/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"pings": fake_check_pings_api_result}))
return_value=Response(
status_code=200, json={"pings": fake_check_pings_api_result}
)
)
pings = await test_async_client.get_check_pings("test") pings = await test_async_client.get_check_pings("test")
assert len(pings) == len(fake_check_pings_api_result) assert len(pings) == len(fake_check_pings_api_result)
assert pings[0].type == fake_check_pings_api_result[0]["type"] assert pings[0].type == fake_check_pings_api_result[0]["type"]
@@ -263,13 +235,9 @@ async def test_aget_check_pings_200(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_aget_check_flips_200( async def test_aget_check_flips_200(fake_check_flips_api_result, respx_mock, test_async_client):
fake_check_flips_api_result, respx_mock, test_async_client
):
checks_url = urljoin(test_async_client._api_url, "checks/test/flips/") checks_url = urljoin(test_async_client._api_url, "checks/test/flips/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_flips_api_result))
return_value=Response(status_code=200, json=fake_check_flips_api_result)
)
flips = await test_async_client.get_check_flips("test") flips = await test_async_client.get_check_flips("test")
assert len(flips) == len(fake_check_flips_api_result) assert len(flips) == len(fake_check_flips_api_result)
assert flips[0].up == fake_check_flips_api_result[0]["up"] assert flips[0].up == fake_check_flips_api_result[0]["up"]
@@ -277,15 +245,9 @@ async def test_aget_check_flips_200(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_get_check_flips_params_200( async def test_get_check_flips_params_200(fake_check_flips_api_result, respx_mock, test_async_client):
fake_check_flips_api_result, respx_mock, test_async_client checks_url = urljoin(test_async_client._api_url, "checks/test/flips/?seconds=1&start=1&end=1")
): respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_flips_api_result))
checks_url = urljoin(
test_async_client._api_url, "checks/test/flips/?seconds=1&start=1&end=1"
)
respx_mock.get(checks_url).mock(
return_value=Response(status_code=200, json=fake_check_flips_api_result)
)
flips = await test_async_client.get_check_flips("test", seconds=1, start=1, end=1) flips = await test_async_client.get_check_flips("test", seconds=1, start=1, end=1)
assert len(flips) == len(fake_check_flips_api_result) assert len(flips) == len(fake_check_flips_api_result)
assert flips[0].up == fake_check_flips_api_result[0]["up"] assert flips[0].up == fake_check_flips_api_result[0]["up"]
@@ -293,9 +255,7 @@ async def test_get_check_flips_params_200(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_aget_check_flips_400( async def test_aget_check_flips_400(fake_check_flips_api_result, respx_mock, test_async_client):
fake_check_flips_api_result, respx_mock, test_async_client
):
flips_url = urljoin(test_async_client._api_url, "checks/test/flips/") flips_url = urljoin(test_async_client._api_url, "checks/test/flips/")
respx_mock.get(flips_url).mock(return_value=Response(status_code=400)) respx_mock.get(flips_url).mock(return_value=Response(status_code=400))
with pytest.raises(BadAPIRequestError): with pytest.raises(BadAPIRequestError):
@@ -304,13 +264,9 @@ async def test_aget_check_flips_400(
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
async def test_aget_integrations( async def test_aget_integrations(fake_integrations_api_result, respx_mock, test_async_client):
fake_integrations_api_result, respx_mock, test_async_client
):
channels_url = urljoin(test_async_client._api_url, "channels/") channels_url = urljoin(test_async_client._api_url, "channels/")
respx_mock.get(channels_url).mock( respx_mock.get(channels_url).mock(return_value=Response(status_code=200, json=fake_integrations_api_result))
return_value=Response(status_code=200, json=fake_integrations_api_result)
)
integrations = await test_async_client.get_integrations() integrations = await test_async_client.get_integrations()
assert len(integrations) == len(fake_integrations_api_result["channels"]) assert len(integrations) == len(fake_integrations_api_result["channels"])
assert integrations[0].id == fake_integrations_api_result["channels"][0]["id"] assert integrations[0].id == fake_integrations_api_result["channels"][0]["id"]
@@ -320,9 +276,7 @@ async def test_aget_integrations(
@pytest.mark.respx @pytest.mark.respx
async def test_aget_badges(fake_badges_api_result, respx_mock, test_async_client): async def test_aget_badges(fake_badges_api_result, respx_mock, test_async_client):
channels_url = urljoin(test_async_client._api_url, "badges/") channels_url = urljoin(test_async_client._api_url, "badges/")
respx_mock.get(channels_url).mock( respx_mock.get(channels_url).mock(return_value=Response(status_code=200, json=fake_badges_api_result))
return_value=Response(status_code=200, json=fake_badges_api_result)
)
integrations = await test_async_client.get_badges() integrations = await test_async_client.get_badges()
assert integrations.keys() == fake_badges_api_result["badges"].keys() assert integrations.keys() == fake_badges_api_result["badges"].keys()
@@ -389,14 +343,10 @@ ping_test_parameters = [
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.respx @pytest.mark.respx
@pytest.mark.parametrize( @pytest.mark.parametrize("respx_mocker, tc, url, ping_method, method_kwargs", ping_test_parameters)
"respx_mocker, tc, url, ping_method, method_kwargs", ping_test_parameters
)
async def test_asuccess_ping(respx_mocker, tc, url, ping_method, method_kwargs): async def test_asuccess_ping(respx_mocker, tc, url, ping_method, method_kwargs):
channels_url = urljoin(tc._ping_url, url) channels_url = urljoin(tc._ping_url, url)
respx_mocker.post(channels_url).mock( respx_mocker.post(channels_url).mock(return_value=Response(status_code=200, text="OK"))
return_value=Response(status_code=200, text="OK")
)
ping_method = getattr(tc, ping_method) ping_method = getattr(tc, ping_method)
result = await ping_method(**method_kwargs) result = await ping_method(**method_kwargs)
assert result[0] is True assert result[0] is True

View File

@@ -76,7 +76,6 @@ async def test_check_trap_async_exception(respx_mock, test_async_client):
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_check_trap_wrong_client_error(test_client, test_async_client): async def test_check_trap_wrong_client_error(test_client, test_async_client):
with pytest.raises(WrongClientError): with pytest.raises(WrongClientError):
async with CheckTrap(test_client, uuid="test"): async with CheckTrap(test_client, uuid="test"):
pass pass

View File

@@ -14,9 +14,7 @@ from healthchecks_io.client.exceptions import HCAPIError
@pytest.mark.respx @pytest.mark.respx
def test_create_check_200_context_manager( def test_create_check_200_context_manager(fake_check_api_result, respx_mock, test_client):
fake_check_api_result, respx_mock, test_client
):
checks_url = urljoin(test_client._api_url, "checks/") checks_url = urljoin(test_client._api_url, "checks/")
respx_mock.post(checks_url).mock( respx_mock.post(checks_url).mock(
return_value=Response( return_value=Response(
@@ -110,9 +108,7 @@ def test_update_check_200(fake_check_api_result, respx_mock, test_client):
def test_get_checks_200(fake_check_api_result, respx_mock, test_client): def test_get_checks_200(fake_check_api_result, respx_mock, test_client):
assert test_client._client is not None assert test_client._client is not None
checks_url = urljoin(test_client._api_url, "checks/") checks_url = urljoin(test_client._api_url, "checks/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"checks": [fake_check_api_result]}))
return_value=Response(status_code=200, json={"checks": [fake_check_api_result]})
)
checks = test_client.get_checks() checks = test_client.get_checks()
assert len(checks) == 1 assert len(checks) == 1
assert checks[0].name == fake_check_api_result["name"] assert checks[0].name == fake_check_api_result["name"]
@@ -121,13 +117,9 @@ def test_get_checks_200(fake_check_api_result, respx_mock, test_client):
@pytest.mark.respx @pytest.mark.respx
def test_get_checks_pass_in_client(fake_check_api_result, respx_mock): def test_get_checks_pass_in_client(fake_check_api_result, respx_mock):
httpx_client = HTTPXClient() httpx_client = HTTPXClient()
test_client = Client( test_client = Client(api_key="test", api_url="http://localhost/api/", client=httpx_client)
api_key="test", api_url="http://localhost/api/", client=httpx_client
)
checks_url = urljoin(test_client._api_url, "checks/") checks_url = urljoin(test_client._api_url, "checks/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"checks": [fake_check_api_result]}))
return_value=Response(status_code=200, json={"checks": [fake_check_api_result]})
)
checks = test_client.get_checks() checks = test_client.get_checks()
assert len(checks) == 1 assert len(checks) == 1
assert checks[0].name == fake_check_api_result["name"] assert checks[0].name == fake_check_api_result["name"]
@@ -169,9 +161,7 @@ def test_finalizer_closes(test_client):
def test_get_check_200(fake_check_api_result, respx_mock, test_client): def test_get_check_200(fake_check_api_result, respx_mock, test_client):
assert test_client._client is not None assert test_client._client is not None
checks_url = urljoin(test_client._api_url, "checks/test") checks_url = urljoin(test_client._api_url, "checks/test")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = test_client.get_check(check_id="test") check = test_client.get_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -188,9 +178,7 @@ def test_check_get_404(respx_mock, test_client):
@pytest.mark.respx @pytest.mark.respx
def test_pause_check_200(fake_check_api_result, respx_mock, test_client): def test_pause_check_200(fake_check_api_result, respx_mock, test_client):
checks_url = urljoin(test_client._api_url, "checks/test/pause") checks_url = urljoin(test_client._api_url, "checks/test/pause")
respx_mock.post(checks_url).mock( respx_mock.post(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = test_client.pause_check(check_id="test") check = test_client.pause_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -208,9 +196,7 @@ def test_check_pause_404(respx_mock, test_client):
def test_delete_check_200(fake_check_api_result, respx_mock, test_client): def test_delete_check_200(fake_check_api_result, respx_mock, test_client):
assert test_client._client is not None assert test_client._client is not None
checks_url = urljoin(test_client._api_url, "checks/test") checks_url = urljoin(test_client._api_url, "checks/test")
respx_mock.delete(checks_url).mock( respx_mock.delete(checks_url).mock(return_value=Response(status_code=200, json=fake_check_api_result))
return_value=Response(status_code=200, json=fake_check_api_result)
)
check = test_client.delete_check(check_id="test") check = test_client.delete_check(check_id="test")
assert check.name == fake_check_api_result["name"] assert check.name == fake_check_api_result["name"]
@@ -226,11 +212,7 @@ def test_delete_pause404(respx_mock, test_client):
@pytest.mark.respx @pytest.mark.respx
def test_get_check_pings_200(fake_check_pings_api_result, respx_mock, test_client): def test_get_check_pings_200(fake_check_pings_api_result, respx_mock, test_client):
checks_url = urljoin(test_client._api_url, "checks/test/pings/") checks_url = urljoin(test_client._api_url, "checks/test/pings/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json={"pings": fake_check_pings_api_result}))
return_value=Response(
status_code=200, json={"pings": fake_check_pings_api_result}
)
)
pings = test_client.get_check_pings("test") pings = test_client.get_check_pings("test")
assert len(pings) == len(fake_check_pings_api_result) assert len(pings) == len(fake_check_pings_api_result)
assert pings[0].type == fake_check_pings_api_result[0]["type"] assert pings[0].type == fake_check_pings_api_result[0]["type"]
@@ -239,24 +221,16 @@ def test_get_check_pings_200(fake_check_pings_api_result, respx_mock, test_clien
@pytest.mark.respx @pytest.mark.respx
def test_get_check_flips_200(fake_check_flips_api_result, respx_mock, test_client): def test_get_check_flips_200(fake_check_flips_api_result, respx_mock, test_client):
checks_url = urljoin(test_client._api_url, "checks/test/flips/") checks_url = urljoin(test_client._api_url, "checks/test/flips/")
respx_mock.get(checks_url).mock( respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_flips_api_result))
return_value=Response(status_code=200, json=fake_check_flips_api_result)
)
flips = test_client.get_check_flips("test") flips = test_client.get_check_flips("test")
assert len(flips) == len(fake_check_flips_api_result) assert len(flips) == len(fake_check_flips_api_result)
assert flips[0].up == fake_check_flips_api_result[0]["up"] assert flips[0].up == fake_check_flips_api_result[0]["up"]
@pytest.mark.respx @pytest.mark.respx
def test_get_check_flips_params_200( def test_get_check_flips_params_200(fake_check_flips_api_result, respx_mock, test_client):
fake_check_flips_api_result, respx_mock, test_client checks_url = urljoin(test_client._api_url, "checks/test/flips/?seconds=1&start=1&end=1")
): respx_mock.get(checks_url).mock(return_value=Response(status_code=200, json=fake_check_flips_api_result))
checks_url = urljoin(
test_client._api_url, "checks/test/flips/?seconds=1&start=1&end=1"
)
respx_mock.get(checks_url).mock(
return_value=Response(status_code=200, json=fake_check_flips_api_result)
)
flips = test_client.get_check_flips("test", seconds=1, start=1, end=1) flips = test_client.get_check_flips("test", seconds=1, start=1, end=1)
assert len(flips) == len(fake_check_flips_api_result) assert len(flips) == len(fake_check_flips_api_result)
assert flips[0].up == fake_check_flips_api_result[0]["up"] assert flips[0].up == fake_check_flips_api_result[0]["up"]
@@ -273,9 +247,7 @@ def test_get_check_flips_400(fake_check_flips_api_result, respx_mock, test_clien
@pytest.mark.respx @pytest.mark.respx
def test_get_integrations(fake_integrations_api_result, respx_mock, test_client): def test_get_integrations(fake_integrations_api_result, respx_mock, test_client):
channels_url = urljoin(test_client._api_url, "channels/") channels_url = urljoin(test_client._api_url, "channels/")
respx_mock.get(channels_url).mock( respx_mock.get(channels_url).mock(return_value=Response(status_code=200, json=fake_integrations_api_result))
return_value=Response(status_code=200, json=fake_integrations_api_result)
)
integrations = test_client.get_integrations() integrations = test_client.get_integrations()
assert len(integrations) == len(fake_integrations_api_result["channels"]) assert len(integrations) == len(fake_integrations_api_result["channels"])
assert integrations[0].id == fake_integrations_api_result["channels"][0]["id"] assert integrations[0].id == fake_integrations_api_result["channels"][0]["id"]
@@ -284,9 +256,7 @@ def test_get_integrations(fake_integrations_api_result, respx_mock, test_client)
@pytest.mark.respx @pytest.mark.respx
def test_get_badges(fake_badges_api_result, respx_mock, test_client): def test_get_badges(fake_badges_api_result, respx_mock, test_client):
channels_url = urljoin(test_client._api_url, "badges/") channels_url = urljoin(test_client._api_url, "badges/")
respx_mock.get(channels_url).mock( respx_mock.get(channels_url).mock(return_value=Response(status_code=200, json=fake_badges_api_result))
return_value=Response(status_code=200, json=fake_badges_api_result)
)
integrations = test_client.get_badges() integrations = test_client.get_badges()
assert integrations.keys() == fake_badges_api_result["badges"].keys() assert integrations.keys() == fake_badges_api_result["badges"].keys()
@@ -352,14 +322,10 @@ ping_test_parameters = [
@pytest.mark.respx @pytest.mark.respx
@pytest.mark.parametrize( @pytest.mark.parametrize("respx_mocker, tc, url, ping_method, method_kwargs", ping_test_parameters)
"respx_mocker, tc, url, ping_method, method_kwargs", ping_test_parameters
)
def test_success_ping(respx_mocker, tc, url, ping_method, method_kwargs): def test_success_ping(respx_mocker, tc, url, ping_method, method_kwargs):
channels_url = urljoin(tc._ping_url, url) channels_url = urljoin(tc._ping_url, url)
respx_mocker.post(channels_url).mock( respx_mocker.post(channels_url).mock(return_value=Response(status_code=200, text="OK"))
return_value=Response(status_code=200, text="OK")
)
ping_method = getattr(tc, ping_method) ping_method = getattr(tc, ping_method)
result, text = ping_method(**method_kwargs) result, text = ping_method(**method_kwargs)
assert result is True assert result is True

View File

@@ -37,27 +37,19 @@ def test_check_create_validators():
# test validate_schedule # test validate_schedule
with pytest.raises(ValidationError): with pytest.raises(ValidationError):
check_create = checks.CheckCreate( check_create = checks.CheckCreate(name="Test", tags="", desc="Test", schedule="no good")
name="Test", tags="", desc="Test", schedule="no good"
)
# test validate_tz # test validate_tz
with pytest.raises(ValidationError): with pytest.raises(ValidationError):
check_create = checks.CheckCreate( check_create = checks.CheckCreate(name="Test", tags="", desc="Test", tz="no good")
name="Test", tags="", desc="Test", tz="no good"
)
# test validate_methods # test validate_methods
with pytest.raises(ValidationError): with pytest.raises(ValidationError):
check_create = checks.CheckCreate( check_create = checks.CheckCreate(name="Test", tags="", desc="Test", methods="no good")
name="Test", tags="", desc="Test", methods="no good"
)
# test validate_unique # test validate_unique
with pytest.raises(ValidationError): with pytest.raises(ValidationError):
check_create = checks.CheckCreate( check_create = checks.CheckCreate(name="Test", tags="", desc="Test", unique=["no good"])
name="Test", tags="", desc="Test", unique=["no good"]
)
def test_check_pings_from_api(): def test_check_pings_from_api():