You've already forked tribes-plugin-supertest
forked from tribes/tribes-plugin-template
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:
@@ -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,
|
||||
%{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
global:
|
||||
scrape_interval: 5s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: tribes
|
||||
metrics_path: /metrics
|
||||
static_configs:
|
||||
- targets: ["127.0.0.1:4000"]
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user