Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(metrics): initial support #5

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
default_language_version:
python: python3.12

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace # Trims trailing whitespace.
- id: end-of-file-fixer # Makes sure files end in a newline and only a newline.
- id: check-added-large-files # Prevent giant files from being committed.
- id: requirements-txt-fixer
- id: check-merge-conflict

- repo: https://github.com/commitizen-tools/commitizen
rev: v3.5.3
hooks:
- id: commitizen
stages:
- commit-msg

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
- id: mypy
entry: mypy
files: send/
language: system
args: [--install-types, --non-interactive]
1 change: 0 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,3 @@ USER nobody:nogroup
EXPOSE 8000

CMD ["python", "typesense_exporter.py", "--port=8000"]

1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,3 @@ This design guarantees that metrics are always up-to-date at scrape time (with n
## License

This exporter is released under the MIT License. See LICENSE for details (or replace with your preferred license).

3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mypy>=1.14
pytest>=7.0
pytest-asyncio>=0.23.5
pytest-cov>=4.1
pytest>=7.0
requests-mock==1.12.1
types-requests>=2.32
89 changes: 89 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import pytest
from typesense_exporter import TypesenseCollector


@pytest.fixture
def response_metrics_json():
yield {
"system_cpu1_active_percentage": "9.09",
"system_cpu2_active_percentage": "0.00",
"system_cpu3_active_percentage": "0.00",
"system_cpu4_active_percentage": "0.00",
"system_cpu_active_percentage": "0.00",
"system_disk_total_bytes": "102888095744",
"system_disk_used_bytes": "4177268736",
"system_memory_total_bytes": "16764186624",
"system_memory_total_swap_bytes": "0",
"system_memory_used_bytes": "3234148352",
"system_memory_used_swap_bytes": "0",
"system_network_received_bytes": "6534814741",
"system_network_sent_bytes": "4613106962",
"typesense_memory_active_bytes": "51126272",
"typesense_memory_allocated_bytes": "43065104",
"typesense_memory_fragmentation_ratio": "0.16",
"typesense_memory_mapped_bytes": "97370112",
"typesense_memory_metadata_bytes": "9009280",
"typesense_memory_resident_bytes": "51126272",
"typesense_memory_retained_bytes": "30556160",
}


@pytest.fixture
def response_stats_json():
yield {
"delete_latency_ms": 0,
"delete_requests_per_second": 0,
"import_latency_ms": 0,
"import_requests_per_second": 0,
"latency_ms": {"GET /health": 0.0, "GET /status": 0.0},
"overloaded_requests_per_second": 0,
"pending_write_batches": 0,
"requests_per_second": {"GET /health": 1.5, "GET /status": 0.6},
"search_latency_ms": 0,
"search_requests_per_second": 0,
"total_requests_per_second": 2.1,
"write_latency_ms": 0,
"write_requests_per_second": 0,
}


@pytest.fixture
def response_debug_json():
yield {"state": 1, "version": "0.24.0"}


@pytest.fixture
def response_collections_json():
yield [
{"name": "products", "num_documents": 100},
{"name": "users", "num_documents": 50},
]


@pytest.fixture(autouse=True)
def mock_typesense_api(
requests_mock,
response_metrics_json,
response_stats_json,
response_debug_json,
response_collections_json,
):
base_url = "http://localhost:8108"

requests_mock.get(f"{base_url}/metrics.json", json=response_metrics_json)
requests_mock.get(f"{base_url}/stats.json", json=response_stats_json)
requests_mock.get(f"{base_url}/debug", json=response_debug_json)
requests_mock.get(f"{base_url}/collections", json=response_collections_json)

yield requests_mock


@pytest.fixture
def typesense_collector():
return TypesenseCollector(
typesense_api_key="123",
metrics_url="http://localhost:8108/metrics.json",
stats_url="http://localhost:8108/stats.json",
debug_url="http://localhost:8108/debug",
nodes=[{"host": "localhost", "port": "8108", "protocol": "http"}],
)
101 changes: 72 additions & 29 deletions tests/test_typesense_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,79 @@
from typesense_exporter import parse_nodes_from_str


@pytest.mark.parametrize("test_input,expected,protocol,description", [
(
"localhost:8108",
[{"host": "localhost", "port": "8108", "protocol": "https"}],
"https",
"single node with port"
),
(
"host1:8108,host2:8108",
[
{"host": "host1", "port": "8108", "protocol": "https"},
{"host": "host2", "port": "8108", "protocol": "https"}
],
"https",
"multiple nodes"
),
(
"localhost",
[{"host": "localhost", "port": "8108", "protocol": "https"}],
"https",
"default port"
),
(
"localhost:8108",
[{"host": "localhost", "port": "8108", "protocol": "http"}],
"http",
"custom protocol"
),
])
@pytest.mark.parametrize(
"test_input,expected,protocol,description",
[
(
"localhost:8108",
[{"host": "localhost", "port": "8108", "protocol": "https"}],
"https",
"single node with port",
),
(
"host1:8108,host2:8108",
[
{"host": "host1", "port": "8108", "protocol": "https"},
{"host": "host2", "port": "8108", "protocol": "https"},
],
"https",
"multiple nodes",
),
(
"localhost",
[{"host": "localhost", "port": "8108", "protocol": "https"}],
"https",
"default port",
),
(
"localhost:8108",
[{"host": "localhost", "port": "8108", "protocol": "http"}],
"http",
"custom protocol",
),
],
)
def test_parse_nodes_from_str(test_input, expected, protocol, description):
nodes = parse_nodes_from_str(test_input, default_protocol=protocol)
assert len(nodes) == len(expected)
assert nodes == expected


def test_typesense_collector_metrics(typesense_collector):
metrics = list(typesense_collector._collect_metrics_json())
assert len(metrics) == 20


def test_typesense_collector_stats(typesense_collector):
metrics = list(typesense_collector._collect_stats_json())
assert len(metrics) == 13


def test_typesense_collector_json(typesense_collector):
metrics = list(typesense_collector._collect_debug_json())
assert len(metrics) == 1


def test_typesense_collector_collections(typesense_collector):
metrics = list(typesense_collector._collect_collections())
assert len(metrics) == 1

metric_family = metrics[0]
assert metric_family.name == "typesense_collection_documents"
assert (
metric_family.documentation
== "Number of documents in each Typesense collection"
)

assert len(metric_family.samples) == 2

sample_1 = metric_family.samples[0]
sample_2 = metric_family.samples[1]

assert sample_1.name == "typesense_collection_documents"
assert sample_1.labels == {"collection_name": "products"}
assert sample_1.value == 100.0

assert sample_2.name == "typesense_collection_documents"
assert sample_2.labels == {"collection_name": "users"}
assert sample_2.value == 50.0
Loading