test: cover plugin metrics rollups

Add a supertest metrics probe that emits telemetry, configure vmagent sidecars in the Docker e2e stack, and assert the emitted plugin metric reaches synced rollups through the admin API.
This commit is contained in:
2026-05-14 15:25:41 +02:00
parent 99a7d68125
commit e45ec84341
9 changed files with 150 additions and 0 deletions
+10
View File
@@ -127,6 +127,16 @@ defmodule Supertest.API do
def received_cluster_pubsub(_params), do: {:error, :invalid_run_id}
def emit_metrics_probe(params) do
value = integer_param(params, "value", nil)
:telemetry.execute([:supertest, :metrics, :probe], %{value: value}, %{})
{:ok, %{ok: true, value: value}}
rescue
error in ArgumentError -> {:error, error.message}
end
def management_echo(context, params) do
{:ok,
%{
+4
View File
@@ -51,6 +51,10 @@ defmodule SupertestWeb.APIPlug do
conn |> send_result(Supertest.API.received_cluster_pubsub(conn.query_params))
end
defp dispatch(conn, ["metrics", "probe"], "POST") do
conn |> send_result(Supertest.API.emit_metrics_probe(conn.body_params))
end
defp dispatch(conn, ["state"], "GET") do
conn |> send_result(Supertest.API.state(conn.query_params))
end
+11
View File
@@ -38,6 +38,17 @@ defmodule Tribes.Plugins.Supertest.Plugin do
description: "Echo plugin management context"
}
],
metrics: [
%{
name: "probe_value",
stat: "last",
query: "last_over_time(plugins_supertest_probe_value[60s])",
description: "Supertest plugin metrics probe value",
event_name: [:supertest, :metrics, :probe],
measurement: :value,
max_series: 1
}
],
children: cluster_pubsub_children(context)
})
end
+3
View File
@@ -54,6 +54,9 @@ docker compose -f "$COMPOSE_FILE" run --rm migrate-peer
echo "==> starting supertest e2e nodes"
docker compose -f "$COMPOSE_FILE" up -d supertest-origin supertest-peer
echo "==> starting supertest e2e metrics scrapers"
docker compose -f "$COMPOSE_FILE" up -d vmagent-origin vmagent-peer
echo "==> running supertest e2e assertions"
set +e
mix run --no-start "$ROOT_DIR/scripts/supertest_e2e_runner.exs"
+54
View File
@@ -33,6 +33,9 @@ defmodule Supertest.E2ERunner do
{:ok, %{"plugin" => "supertest", "ok" => true}} = supertest_get("supertest-origin", "/health")
{:ok, %{"plugin" => "supertest", "ok" => true}} = supertest_get("supertest-peer", "/health")
metrics_probe_value = 100_000 + System.unique_integer([:positive, :monotonic])
emit_supertest_metrics_probe!(metrics_probe_value)
{:ok, %{"schema" => schema}} = supertest_get("supertest-origin", "/schema")
assert_ok(schema["tables"]["cases"] == true, "supertest cases table exists")
assert_ok(schema["tables"]["events"] == true, "supertest events table exists")
@@ -77,9 +80,21 @@ defmodule Supertest.E2ERunner do
assert_ok(run_cluster_pubsub_probe(run_id) == :ok, "supertest cluster PubSub probe")
assert_ok(
wait_for_supertest_metric_rollup(@origin, metrics_probe_value) == :ok,
"supertest plugin metric appears in rollup"
)
IO.puts("supertest e2e assertions passed")
end
defp emit_supertest_metrics_probe!(value) do
{:ok, %{"ok" => true, "value" => ^value}} =
supertest_post("supertest-origin", "/metrics/probe", %{"value" => value})
:ok
end
defp reset_supertest_state!(run_id) do
{:ok, _} = supertest_post("supertest-origin", "/reset", %{"run_id" => run_id})
{:ok, _} = supertest_post("supertest-peer", "/reset", %{"run_id" => run_id})
@@ -148,6 +163,45 @@ defmodule Supertest.E2ERunner do
end)
end
defp wait_for_supertest_metric_rollup(base_url, expected_value) do
Enum.reduce_while(1..150, {:error, :timeout}, fn _attempt, _acc ->
case admin(base_url, "metrics_rollups.list", %{"limit" => 120}) do
{:ok, %{"rollups" => rollups}} ->
if Enum.any?(rollups, &supertest_metric_rollup?(&1, expected_value)) do
{:halt, :ok}
else
Process.sleep(1_000)
{:cont, {:error, rollups}}
end
other ->
Process.sleep(1_000)
{:cont, other}
end
end)
end
defp supertest_metric_rollup?(%{"plugins" => plugins}, expected_value) when is_map(plugins) do
plugins
|> get_in(["supertest", "probe_value", "last"])
|> numeric_equal?(expected_value)
end
defp supertest_metric_rollup?(_rollup, _expected_value), do: false
defp numeric_equal?(value, expected) when is_integer(value) or is_float(value) do
value == expected
end
defp numeric_equal?(value, expected) when is_binary(value) do
case Float.parse(value) do
{parsed, ""} -> parsed == expected
_other -> false
end
end
defp numeric_equal?(_value, _expected), do: false
defp has_case?(%{"cases" => cases}, case_id, counter) when is_list(cases) do
Enum.any?(cases, fn
%{"id" => ^case_id, "counter" => ^counter} -> true
+31
View File
@@ -56,6 +56,7 @@ services:
PARRHESIA_RELAY_URL: ws://supertest-origin:4000/nostr/relay
PARRHESIA_IDENTITY_PRIVATE_KEY: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
TRIBES_VICTORIAMETRICS_URL: http://vm-origin:8428
TRIBES_METRICS_ALLOWED_CIDRS: 0.0.0.0/0,::/0
command: ["eval", "Tribes.Release.migrate_with_storage_up()"]
migrate-peer:
@@ -90,6 +91,21 @@ services:
- "47201:4413"
command: ["start"]
vmagent-origin:
image: victoriametrics/vmagent:v1.138.0
network_mode: "service:supertest-origin"
depends_on:
supertest-origin:
condition: service_started
vm-origin:
condition: service_started
volumes:
- ${SUPERTEST_PLUGIN_ROOT}/test/e2e/vmagent/promscrape.yml:/etc/vmagent/promscrape.yml:ro
command:
- -promscrape.config=/etc/vmagent/promscrape.yml
- -remoteWrite.url=http://vm-origin:8428/api/v1/write
- -httpListenAddr=127.0.0.1:8429
supertest-peer:
image: ${TRIBES_SUPERTEST_IMAGE:-tribes-supertest-e2e:latest}
depends_on:
@@ -112,3 +128,18 @@ services:
- "46202:4000"
- "47202:4413"
command: ["start"]
vmagent-peer:
image: victoriametrics/vmagent:v1.138.0
network_mode: "service:supertest-peer"
depends_on:
supertest-peer:
condition: service_started
vm-peer:
condition: service_started
volumes:
- ${SUPERTEST_PLUGIN_ROOT}/test/e2e/vmagent/promscrape.yml:/etc/vmagent/promscrape.yml:ro
command:
- -promscrape.config=/etc/vmagent/promscrape.yml
- -remoteWrite.url=http://vm-peer:8428/api/v1/write
- -httpListenAddr=127.0.0.1:8429
+8
View File
@@ -0,0 +1,8 @@
global:
scrape_interval: 5s
scrape_configs:
- job_name: tribes
metrics_path: /metrics
static_configs:
- targets: ["127.0.0.1:4000"]
+11
View File
@@ -52,4 +52,15 @@ defmodule SupertestWeb.APIPlugTest do
assert conn.status == 200
assert %{"ok" => true} = Jason.decode!(conn.resp_body)
end
test "serves metrics probe route for loopback requests" do
conn =
:post
|> build_conn("/plugins-api/supertest/metrics/probe", %{value: 41})
|> Map.put(:remote_ip, {127, 0, 0, 1})
|> SupertestWeb.APIPlug.call([])
assert conn.status == 200
assert %{"ok" => true, "value" => 41} = Jason.decode!(conn.resp_body)
end
end
+18
View File
@@ -132,6 +132,24 @@ defmodule Supertest.APITest do
assert actor_pubkey == String.duplicate("a", 64)
end
test "emits metrics probe telemetry" do
ref = make_ref()
:telemetry.attach(
"supertest-api-metrics-probe-test",
[:supertest, :metrics, :probe],
fn _event, measurements, metadata, pid ->
send(pid, {ref, measurements, metadata})
end,
self()
)
on_exit(fn -> :telemetry.detach("supertest-api-metrics-probe-test") end)
assert {:ok, %{ok: true, value: 41}} = Supertest.API.emit_metrics_probe(%{"value" => 41})
assert_receive {^ref, %{value: 41}, %{}}
end
defp eventually(assertion, attempts \\ 20)
defp eventually(assertion, attempts) when attempts > 0 do