From ca0228a961cbec97b505db53acf78dec5ee87bf0 Mon Sep 17 00:00:00 2001 From: marun Date: Wed, 4 Sep 2024 07:14:46 -0700 Subject: [PATCH] [e2e] Emit a duration-scoped grafana link for each test (#3340) Signed-off-by: marun Co-authored-by: Stephen Buttolph --- tests/e2e/c/dynamic_fees.go | 7 ++++ tests/fixture/e2e/env.go | 3 ++ tests/fixture/e2e/flags.go | 9 +++-- tests/fixture/e2e/metrics_link.go | 55 +++++++++++++++++++++++++++++++ tests/fixture/tmpnet/network.go | 22 ++++++++++++- 5 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 tests/fixture/e2e/metrics_link.go diff --git a/tests/e2e/c/dynamic_fees.go b/tests/e2e/c/dynamic_fees.go index 6b554087a996..409d41056e1f 100644 --- a/tests/e2e/c/dynamic_fees.go +++ b/tests/e2e/c/dynamic_fees.go @@ -39,6 +39,13 @@ var _ = e2e.DescribeCChain("[Dynamic Fees]", func() { privateNetwork := tmpnet.NewDefaultNetwork("avalanchego-e2e-dynamic-fees") e2e.GetEnv(tc).StartPrivateNetwork(privateNetwork) + // Avoid emitting a spec-scoped metrics link for the shared + // network since the link emitted by the start of the private + // network is more relevant. + // + // TODO(marun) Make this implicit to the start of a private network + e2e.EmitMetricsLink = false + tc.By("allocating a pre-funded key") key := privateNetwork.PreFundedKeys[0] ethAddress := evm.GetEthAddress(key) diff --git a/tests/fixture/e2e/env.go b/tests/fixture/e2e/env.go index a8b10c19c9fa..f39961dfb522 100644 --- a/tests/fixture/e2e/env.go +++ b/tests/fixture/e2e/env.go @@ -58,6 +58,9 @@ type TestEnvironment struct { // Retrieve the test environment configured with the provided test context. func GetEnv(tc tests.TestContext) *TestEnvironment { + if env == nil { + return nil + } return &TestEnvironment{ NetworkDir: env.NetworkDir, URIs: env.URIs, diff --git a/tests/fixture/e2e/flags.go b/tests/fixture/e2e/flags.go index 05d698ce6262..f87132b0c974 100644 --- a/tests/fixture/e2e/flags.go +++ b/tests/fixture/e2e/flags.go @@ -12,6 +12,10 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" ) +// Ensure that this value takes into account the scrape_interval +// defined in scripts/run_prometheus.sh. +const networkShutdownDelay = 12 * time.Second + type FlagVars struct { avalancheGoExecPath string pluginDir string @@ -52,9 +56,8 @@ func (v *FlagVars) RestartNetwork() bool { func (v *FlagVars) NetworkShutdownDelay() time.Duration { if v.delayNetworkShutdown { - // Only return a non-zero value if the delay is enabled. Make sure this value takes - // into account the scrape_interval defined in scripts/run_prometheus.sh. - return 12 * time.Second + // Only return a non-zero value if the delay is enabled. + return networkShutdownDelay } return 0 } diff --git a/tests/fixture/e2e/metrics_link.go b/tests/fixture/e2e/metrics_link.go new file mode 100644 index 000000000000..97ccd7e7d3d9 --- /dev/null +++ b/tests/fixture/e2e/metrics_link.go @@ -0,0 +1,55 @@ +// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package e2e + +import ( + "strconv" + "time" + + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + + ginkgo "github.com/onsi/ginkgo/v2" +) + +// The ginkgo event handlers defined in this file will be automatically +// applied to all ginkgo suites importing this package. + +// Whether a spec-scoped metrics link should be emitted after the current +// spec finishes executing. +var EmitMetricsLink bool + +// This event handler ensures that by default a spec-scoped metrics link +// will be emitted at the end of spec execution. If the test uses a +// private network, it can disable this behavior by setting +// EmitMetricsLink to false. +// +// TODO(marun) Make this conditional on metrics collection being enabled +var _ = ginkgo.BeforeEach(func() { + EmitMetricsLink = true +}) + +// This event handler attempts to emit a metrics link scoped to the duration +// of the current spec. +// +// TODO(marun) Make this conditional on metrics collection being enabled +var _ = ginkgo.AfterEach(func() { + tc := NewTestContext() + env := GetEnv(tc) + if env == nil || !EmitMetricsLink { + return + } + + specReport := ginkgo.CurrentSpecReport() + startTime := specReport.StartTime.UnixMilli() + // Extend the end time by the shutdown delay (a proxy for the metrics + // scrape interval) to maximize the chances of the specified duration + // including all metrics relevant to the current spec. + endTime := time.Now().Add(networkShutdownDelay).UnixMilli() + metricsLink := tmpnet.MetricsLinkForNetwork( + env.GetNetwork().UUID, + strconv.FormatInt(startTime, 10), + strconv.FormatInt(endTime, 10), + ) + tc.Outf("Test Metrics: %s\n", metricsLink) +}) diff --git a/tests/fixture/tmpnet/network.go b/tests/fixture/tmpnet/network.go index 3eec5cdf7a06..96798b063b3b 100644 --- a/tests/fixture/tmpnet/network.go +++ b/tests/fixture/tmpnet/network.go @@ -373,7 +373,9 @@ func (n *Network) StartNodes(ctx context.Context, w io.Writer, nodesToStart ...* return err } // Provide a link to the main dashboard filtered by the uuid and showing results from now till whenever the link is viewed - if _, err := fmt.Fprintf(w, "\nMetrics: https://grafana-poc.avax-dev.network/d/kBQpRdWnk/avalanche-main-dashboard?&var-filter=network_uuid%%7C%%3D%%7C%s&var-filter=is_ephemeral_node%%7C%%3D%%7Cfalse&from=%d&to=now\n", n.UUID, startTime.UnixMilli()); err != nil { + startTimeStr := strconv.FormatInt(startTime.UnixMilli(), 10) + metricsURL := MetricsLinkForNetwork(n.UUID, startTimeStr, "") + if _, err := fmt.Fprintf(w, "\nMetrics: %s\n", metricsURL); err != nil { return err } @@ -1009,3 +1011,21 @@ func getRPCVersion(command string, versionArgs ...string) (uint64, error) { return version.RPCChainVM, nil } + +// MetricsLinkForNetwork returns a link to the default metrics dashboard for the network +// with the given UUID. The start and end times are accepted as strings to support the +// use of Grafana's time range syntax (e.g. `now`, `now-1h`). +func MetricsLinkForNetwork(networkUUID string, startTime string, endTime string) string { + if startTime == "" { + startTime = "now-1h" + } + if endTime == "" { + endTime = "now" + } + return fmt.Sprintf( + "https://grafana-poc.avax-dev.network/d/kBQpRdWnk/avalanche-main-dashboard?&var-filter=network_uuid%%7C%%3D%%7C%s&var-filter=is_ephemeral_node%%7C%%3D%%7Cfalse&from=%s&to=%s", + networkUUID, + startTime, + endTime, + ) +}