Skip to content
Merged
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
1 change: 1 addition & 0 deletions charms/planner-operator/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
--only-binary=pluggy
ops==3.6.0
paas-charm==1.11.1
requests==2.33.0
9 changes: 0 additions & 9 deletions charms/planner-operator/src/charm.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import dataclasses
import json
import logging
import pathlib
import typing

import ops
Expand Down Expand Up @@ -62,14 +61,6 @@ def __init__(self, *args: typing.Any) -> None:
self._on_planner_relation_broken,
)

def get_cos_dir(self) -> str:
"""Get the COS directory for this charm.

Returns:
The COS directory.
"""
return str((pathlib.Path(__file__).parent / "cos").absolute())

def _create_app(self):
"""Patch _create_app to add OpenTelemetry environment variables."""
original_app = super()._create_app()
Expand Down
Empty file.
Empty file.
18 changes: 18 additions & 0 deletions charms/tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,24 @@ def integrate_planner_rabbitmq_postgresql_fixture(
return planner_app


@pytest.fixture(scope="module", name="any_charm_grafana_consumer_app")
def deploy_any_charm_grafana_consumer_app_fixture(juju: jubilant.Juju) -> str:
"""Deploy any charm to act as a grafana-dashboard consumer."""
app_name = "grafana-consumer"

juju.deploy(
"any-charm",
app=app_name,
channel="latest/beta",
)
juju.wait(
lambda status: jubilant.all_active(status, app_name),
timeout=10 * 60,
delay=10,
)
return app_name


@pytest.fixture(scope="module", name="any_charm_github_runner_app")
def deploy_any_charm_github_runner_app_fixture(juju: jubilant.Juju) -> str:
"""Deploy any charm to act as a GitHub runner application."""
Expand Down
31 changes: 31 additions & 0 deletions charms/tests/integration/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2026 Canonical Ltd.
# See LICENSE file for licensing details.
import json
import time
from typing import Any

import jubilant


def poll_grafana_dashboard_templates(
juju: jubilant.Juju, consumer_unit: str, attempts: int = 24, interval: int = 5
) -> dict[str, Any]:
"""Poll for dashboard templates via the grafana-dashboard consumer's relation data.

Checks show-unit on the consumer side, where application-data contains
the provider's data (including the dashboards key).
Returns the templates dict if found, or an empty dict after all attempts are exhausted.
"""
for _ in range(attempts):
stdout = juju.cli("show-unit", consumer_unit, "--format=json")
result = json.loads(stdout)
for relation in result[consumer_unit]["relation-info"]:
if relation["endpoint"] == "require-grafana-dashboard":
dashboards_raw = relation["application-data"].get("dashboards")
if dashboards_raw:
dashboards = json.loads(dashboards_raw)
templates = dashboards.get("templates", {})
if templates:
return templates
time.sleep(interval)
return {}
33 changes: 33 additions & 0 deletions charms/tests/integration/test_planner.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Copyright 2025 Canonical Ltd.
# See LICENSE file for licensing details.
import base64
import json
import lzma
import time

import jubilant
import pytest
import requests
from tests.integration.helpers import poll_grafana_dashboard_templates

APP_PORT = 8080
METRICS_PORT = 9464
Expand Down Expand Up @@ -204,6 +208,35 @@ def test_planner_enable_disable_flavor_actions(
assert flavor_data["is_disabled"] is False, "Flavor should be enabled after action"


@pytest.mark.usefixtures("planner_with_integrations")
def test_planner_grafana_dashboard(
juju: jubilant.Juju,
planner_app: str,
any_charm_grafana_consumer_app: str,
):
"""
arrange: The planner app is deployed with required integrations.
act: Integrate with a grafana-dashboard consumer and inspect relation data.
assert: The grafana-dashboard relation contains dashboard templates including
the custom planner dashboard with planner-specific metrics.
"""
juju.integrate(
f"{planner_app}:grafana-dashboard",
f"{any_charm_grafana_consumer_app}:require-grafana-dashboard",
)

templates = poll_grafana_dashboard_templates(juju, f"{any_charm_grafana_consumer_app}/0")
assert templates, "expected non-empty dashboard templates in grafana-dashboard relation"

all_content = ""
for template in templates.values():
raw = base64.b64decode(template["content"].encode("utf-8"))
all_content += lzma.decompress(raw).decode("utf-8")
assert "github_runner_planner_webhook_consumed_total" in all_content, (
"expected custom planner dashboard with planner-specific metrics"
)


def poll_flavor_status(unit_ip, flavor_name, token, expected_status, attempts=24, interval=5):
"""Poll the flavor API until the expected HTTP status is returned."""
for _ in range(attempts):
Expand Down
21 changes: 21 additions & 0 deletions charms/tests/integration/test_webhook_gateway.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jubilant
import pytest
import requests
from tests.integration.helpers import poll_grafana_dashboard_templates

APP_PORT = 8080
METRICS_PORT = 9464
Expand Down Expand Up @@ -51,3 +52,23 @@ def test_webhook_gateway_prometheus_metrics(
response = requests.get(f"http://{unit_ip}:{METRICS_PORT}/metrics")

assert response.status_code == requests.status_codes.codes.OK


@pytest.mark.usefixtures("webhook_gateway_with_rabbitmq")
def test_webhook_gateway_grafana_dashboard(
juju: jubilant.Juju,
webhook_gateway_app: str,
any_charm_grafana_consumer_app: str,
):
"""
arrange: The webhook gateway app is deployed with required integrations.
act: Integrate with a grafana-dashboard consumer and inspect relation data.
assert: The grafana-dashboard relation contains non-empty dashboard templates.
"""
juju.integrate(
f"{webhook_gateway_app}:grafana-dashboard",
f"{any_charm_grafana_consumer_app}:require-grafana-dashboard",
)

templates = poll_grafana_dashboard_templates(juju, f"{any_charm_grafana_consumer_app}/0")
assert templates, "expected non-empty dashboard templates in grafana-dashboard relation"
1 change: 1 addition & 0 deletions charms/webhook-gateway-operator/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--only-binary=pluggy
ops==3.6.0
paas-charm==1.11.1
Loading