Skip to content

Commit

Permalink
v1.1.0 add tests (#22)
Browse files Browse the repository at this point in the history
* Add project config

* Add python version

* Fix Target defaults

* Add tests

* Update docs

* Update version to 1.1.0

* Sync requirements.txt with uv.lock

* Add CI workflow

* Add pre-commit autoupdate workflow

* Fix README

* Align setup.py with pyproject.toml

* Fix generation of requirements.txt

* Use hashes and add uv export

* Fix uv export

* Use python 3.8

* Be explicit in what to add to docker image

* Add Earthfile
  • Loading branch information
idsvandermolen committed Sep 20, 2024
1 parent 0ed2b76 commit 1bdbcda
Show file tree
Hide file tree
Showing 17 changed files with 573 additions and 29 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Integration

on:
push:

jobs:
uv-example:
name: python
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v2

- name: Set up Python
run: uv python install

- name: Install the project
run: uv sync --all-extras --dev

- name: Run tests
run: uv run pytest

- name: Setup earthly
uses: earthly/actions-setup@v1
with:
version: v0.8.4

- name: Checkout
uses: actions/checkout@v4

- name: Run earthly
run: earthly --ci --output +all

- name: Checking git diff after build
run: git diff --exit-code
28 changes: 28 additions & 0 deletions .github/workflows/pre-commit-autoupdate.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Pre-commit auto-update
on:
workflow_dispatch:
schedule:
- cron: '3 0 1 * *'

jobs:
auto-update:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install pre-commit
shell: bash
- run: pre-commit autoupdate --config .pre-commit-config.yaml --freeze
shell: bash
- uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
branch: update/pre-commit-hooks
title: Update pre-commit hooks
commit-message: "chore: update pre-commit hooks"
body: Update versions of pre-commit hooks to latest version.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
dist
json_exporter.egg-info
build
tests
*.pyc
12 changes: 11 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.4
rev: ef9b09598d53bbcde9cd388ac73a145e67537b44 # frozen: v0.6.6
hooks:
# Run the linter.
- id: ruff
args: [--fix]
# Run the formatter.
- id: ruff-format
- repo: https://github.com/astral-sh/uv-pre-commit
# uv version.
rev: cd08150eb312f2ab81d718d3909493d07cc73bf0 # frozen: 0.4.13
hooks:
- id: uv-export
args:
- --frozen
- --no-dev
- --no-hashes
- --output-file=requirements.txt
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.8
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

## [1.1.0] - 2024-09-20
## Changed
- Add `pyproject.toml`
- Add `uv.lock`
- Add/fix defaults to `Target` class `__init__`
- Add basic tests

## [1.0.1] - 2024-09-11
## Changed
- Upgrade PyYAML from 6.0 to 6.0.2
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
FROM python:3.12-alpine
FROM python:3.8-alpine

ARG USERNAME=json_exporter

ADD ./ /tmp/code
ADD pyproject.toml requirements.txt /tmp/code/
ADD json_exporter /tmp/code/json_exporter/

WORKDIR /tmp/code

Expand Down
20 changes: 20 additions & 0 deletions Earthfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
VERSION 0.8

docker:
ARG USERARCH
FROM DOCKERFILE --build-arg ARCH=$USERARCH .
ARG EARTHLY_GIT_SHORT_HASH
ARG SHORT_SHA=$EARTHLY_GIT_SHORT_HASH
ARG _IMAGE=json_exporter
ARG TAG_NAME=latest

SAVE IMAGE $_IMAGE:$SHORT_SHA
SAVE IMAGE $_IMAGE:$TAG_NAME

tests:
BUILD +docker
FROM +docker
RUN /usr/local/bin/json_exporter --help

all:
BUILD +tests
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,39 @@ logging:
targets: []
```
1. build the container image with `docker build -t json_exporter .`
1. run the container with `docker run -it --rm -p 8000:8000 -v `pwd`:/workspace json_exporter /workspace/test.yaml`
1. run the container with
```bash
docker run -it --rm -p 8000:8000 -v `pwd`:/workspace json_exporter /workspace/test.yaml
```
1. in a separate window check if you get metrics:
```bash
curl -sv localhost:8000
```
## Development
Setup python:
```bash
uv python install 3.8
uv python pin 3.8
```
Setup virtualenv:
```bash
uv sync
```
Run tests:
```bash
uv run pytest
```
### Before release
* update `__version__` in `json_exporter/__init__.py`
* update `Changelog.md`
* run:
```bash
uv export --no-dev --frozen --no-hashes > requirements.txt
```
* test package build:
```bash
uv build
```
### Release
After new version has been merged into master:
* create Github release
2 changes: 1 addition & 1 deletion json_exporter/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.0.1"
__version__ = "1.1.0"
28 changes: 14 additions & 14 deletions json_exporter/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,21 +306,21 @@ class Target(object):
def __init__(
self,
name,
method,
url,
params,
headers,
body,
timeout,
ca_bundle,
strftime,
strftime_utc,
method="GET",
url="http://example.org",
params=None,
headers=None,
body=None,
timeout=TIMEOUT,
ca_bundle=True,
strftime="",
strftime_utc=True,
):
self.name = name
self.method = method
self.url = url
self.params = str_params(params)
self.headers = headers
self.params = str_params(params if params else {})
self.headers = headers if headers else {}
self.body = body
self.timeout = timeout
self.session = requests.Session()
Expand Down Expand Up @@ -448,9 +448,9 @@ def read_target_config(self, target, glb_timeout, glb_ca_bundle, target_idx):
target_name = read_from(target, "name")
method = read_from(target, "method", "GET")
url = read_from(target, "url")
params = read_from(target, "params", {})
headers = read_from(target, "headers", {})
body = read_from(target, "body", None)
params = read_from(target, "params")
headers = read_from(target, "headers")
body = read_from(target, "body")
timeout = read_from(target, "timeout", glb_timeout)
ca_bundle = read_from(target, "ca_bundle", glb_ca_bundle)
strftime = read_from(target, "strftime", "")
Expand Down
44 changes: 44 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[project]
name = "json_exporter"
dynamic = [
"version"
]
description = "Export metrics from JSON HTTP(S) API endpoints"
readme = "README.md"
authors = [
{name = "Ids van der Molen", email = "i.van.der.molen@catawiki.nl"}
]
license.file = "LICENSE.TXT"
requires-python = ">=3.8"
keywords = ["prometheus", "json", "exporter"]
classifiers = [
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
"Development Status :: 5 - Production/Stable",
# Indicate who your project is intended for
"Intended Audience :: Developers",
# pick a classifier from https://pypi.python.org/pypi?%3Aaction=list_classifiers
"Topic :: Utilities",
# Pick your license as you wish (should match "license" above)
# or choose from https://choosealicense.com
"License :: OSI Approved :: MIT License",
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
"Programming Language :: Python :: 3",
]
dependencies = [
"jsonpath-ng==1.5.3",
"prometheus-client==0.12.0",
"pyyaml==6.0.2",
"requests==2.32.0",
]

[tool.uv]
dev-dependencies = [
"pytest>=8.3.3",
]

[project.scripts]
json_exporter = "json_exporter.main:main"
14 changes: 8 additions & 6 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
certifi==2024.7.4
charset-normalizer==2.0.9
decorator==5.1.0
idna==3.7
# This file was autogenerated by uv via the following command:
# uv export --frozen --no-dev --no-hashes --output-file=requirements.txt
certifi==2024.8.30
charset-normalizer==3.3.2
decorator==5.1.1
idna==3.10
jsonpath-ng==1.5.3
ply==3.11
prometheus-client==0.12.0
PyYAML==6.0.2
pyyaml==6.0.2
requests==2.32.0
six==1.16.0
urllib3==1.26.19
urllib3==2.2.3
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@
# Specify the Python versions you support here. In particular, ensure
# that you indicate whether you support Python 2, Python 3 or both.
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.8",
],
keywords="prometheus json exporter",
packages=find_packages(),
install_requires=[
"jsonpath-ng==1.5.3",
"prometheus-client==0.12.0",
"PyYAML==6.0.2",
"pyyaml==6.0.2",
"requests==2.32.0",
],
python_requires=">=3.6",
python_requires=">=3.8",
py_modules=[],
entry_points={"console_scripts": ["json_exporter = json_exporter.main:main"]},
)
Empty file added tests/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions tests/test_jsoncollector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from json_exporter import main
from prometheus_client.metrics_core import Metric


def test_empty_config():
collector = main.JSONCollector({})
assert list(collector.collect()) == []


class MockTarget(main.Target):
def scrape(self):
self.metric_families = []
for rule in self.rules:
for family in rule.get_metric_families(self.data):
self.metric_families.append(family)


def test_simple_rule():
collector = main.JSONCollector({})
target = MockTarget("test_target")
target.data = {"metric1": 1}
rule_config = {"name": "test_rule"}
rule = collector.read_rule_config(rule_config, target.name, 0)
target.add_rule(rule)
collector.targets = [target]
results = list(collector.collect())
assert isinstance(results[0], Metric)
Loading

0 comments on commit 1bdbcda

Please sign in to comment.