moved tests into exporter_test and slots_test

This commit is contained in:
Matt Johnstone 2024-06-15 12:04:07 +02:00
parent 81845a0b7d
commit f834359575
No known key found for this signature in database
GPG Key ID: 7D96C656728409F9
4 changed files with 402 additions and 412 deletions

View File

@ -1,246 +0,0 @@
package main
import (
"context"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestSolanaCollector_Collect_Dynamic(t *testing.T) {
client := newDynamicRPCClient()
collector := createSolanaCollector(client, slotPacerSchedule)
prometheus.NewPedanticRegistry().MustRegister(collector)
// start off by testing initial state:
testCases := []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 3
solana_active_validators{state="delinquent"} 0
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 1000000
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 1000000
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 1000000
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 0
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 0
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 0
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="v1.0.0"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
// now make some changes:
client.UpdateStake("aaa", 2_000_000)
client.UpdateStake("bbb", 500_000)
client.UpdateDelinquency("ccc", true)
client.UpdateVersion("v1.2.3")
// now test the final state
testCases = []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 2
solana_active_validators{state="delinquent"} 1
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 2000000
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 500000
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 1000000
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 0
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 0
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 0
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 1
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="v1.2.3"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
}
type slotMetricValues struct {
SlotHeight float64
TotalTransactions float64
EpochNumber float64
EpochFirstSlot float64
EpochLastSlot float64
}
func getSlotMetricValues() slotMetricValues {
return slotMetricValues{
SlotHeight: testutil.ToFloat64(confirmedSlotHeight),
TotalTransactions: testutil.ToFloat64(totalTransactionsTotal),
EpochNumber: testutil.ToFloat64(currentEpochNumber),
EpochFirstSlot: testutil.ToFloat64(epochFirstSlot),
EpochLastSlot: testutil.ToFloat64(epochLastSlot),
}
}
func TestSolanaCollector_WatchSlots_Dynamic(t *testing.T) {
// reset metrics before running tests:
leaderSlotsTotal.Reset()
leaderSlotsByEpoch.Reset()
// create clients:
client := newDynamicRPCClient()
collector := createSolanaCollector(client, 300*time.Millisecond)
prometheus.NewPedanticRegistry().MustRegister(collector)
// start client/collector and wait a bit:
runCtx, runCancel := context.WithCancel(context.Background())
defer runCancel()
go client.Run(runCtx)
time.Sleep(time.Second)
slotsCtx, slotsCancel := context.WithCancel(context.Background())
defer slotsCancel()
go collector.WatchSlots(slotsCtx)
time.Sleep(time.Second)
initial := getSlotMetricValues()
// wait a bit:
var epochChanged bool
for i := 0; i < 5; i++ {
// wait a bit then get new metrics
time.Sleep(time.Second)
final := getSlotMetricValues()
// make sure things are changing correctly:
assertSlotMetricsChangeCorrectly(t, initial, final)
// sense check to make sure the exporter is not "ahead" of the client (due to double counting or whatever)
assert.LessOrEqualf(
t,
int(final.SlotHeight),
client.Slot,
"Exporter slot (%v) ahead of client slot (%v)!",
int(final.SlotHeight),
client.Slot,
)
assert.LessOrEqualf(
t,
int(final.TotalTransactions),
client.TransactionCount,
"Exporter transaction count (%v) ahead of client transaction count (%v)!",
int(final.TotalTransactions),
client.TransactionCount,
)
assert.LessOrEqualf(
t,
int(final.EpochNumber),
client.Epoch,
"Exporter epoch (%v) ahead of client epoch (%v)!",
int(final.EpochNumber),
client.Epoch,
)
// check if epoch changed
if final.EpochNumber > initial.EpochNumber {
epochChanged = true
}
// make current final the new initial (for next iteration)
initial = final
}
// epoch should have changed somewhere
assert.Truef(t, epochChanged, "Epoch has not changed!")
}
func assertSlotMetricsChangeCorrectly(t *testing.T, initial slotMetricValues, final slotMetricValues) {
// make sure that things have increased
assert.Greaterf(
t,
final.SlotHeight,
initial.SlotHeight,
"Slot has not increased! (%v -> %v)",
initial.SlotHeight,
final.SlotHeight,
)
assert.Greaterf(
t,
final.TotalTransactions,
initial.TotalTransactions,
"Total transactions have not increased! (%v -> %v)",
initial.TotalTransactions,
final.TotalTransactions,
)
assert.GreaterOrEqualf(
t,
final.EpochNumber,
initial.EpochNumber,
"Epoch number has decreased! (%v -> %v)",
initial.EpochNumber,
final.EpochNumber,
)
}

View File

@ -354,3 +354,191 @@ func runCollectionTests(t *testing.T, collector prometheus.Collector, testCases
})
}
}
func TestSolanaCollector_Collect_Static(t *testing.T) {
collector := createSolanaCollector(
&staticRPCClient{},
slotPacerSchedule,
)
prometheus.NewPedanticRegistry().MustRegister(collector)
testCases := []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 2
solana_active_validators{state="delinquent"} 1
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 49
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 42
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 43
`,
},
{
Name: "solana_validator_last_vote",
ExpectedResponse: `
# HELP solana_validator_last_vote Last voted slot per validator
# TYPE solana_validator_last_vote gauge
solana_validator_last_vote{nodekey="aaa",pubkey="AAA"} 92
solana_validator_last_vote{nodekey="bbb",pubkey="BBB"} 147
solana_validator_last_vote{nodekey="ccc",pubkey="CCC"} 148
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 3
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 18
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 19
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 1
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="1.16.7"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
}
func TestSolanaCollector_Collect_Dynamic(t *testing.T) {
client := newDynamicRPCClient()
collector := createSolanaCollector(client, slotPacerSchedule)
prometheus.NewPedanticRegistry().MustRegister(collector)
// start off by testing initial state:
testCases := []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 3
solana_active_validators{state="delinquent"} 0
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 1000000
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 1000000
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 1000000
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 0
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 0
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 0
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="v1.0.0"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
// now make some changes:
client.UpdateStake("aaa", 2_000_000)
client.UpdateStake("bbb", 500_000)
client.UpdateDelinquency("ccc", true)
client.UpdateVersion("v1.2.3")
// now test the final state
testCases = []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 2
solana_active_validators{state="delinquent"} 1
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 2000000
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 500000
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 1000000
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 0
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 0
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 0
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 1
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="v1.2.3"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
}

View File

@ -0,0 +1,214 @@
package main
import (
"context"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
type slotMetricValues struct {
SlotHeight float64
TotalTransactions float64
EpochNumber float64
EpochFirstSlot float64
EpochLastSlot float64
}
func getSlotMetricValues() slotMetricValues {
return slotMetricValues{
SlotHeight: testutil.ToFloat64(confirmedSlotHeight),
TotalTransactions: testutil.ToFloat64(totalTransactionsTotal),
EpochNumber: testutil.ToFloat64(currentEpochNumber),
EpochFirstSlot: testutil.ToFloat64(epochFirstSlot),
EpochLastSlot: testutil.ToFloat64(epochLastSlot),
}
}
func testBlockProductionMetric(
t *testing.T,
metric *prometheus.CounterVec,
host string,
status string,
) {
hostInfo := staticBlockProduction.Hosts[host]
// get expected value depending on status:
var expectedValue float64
switch status {
case "valid":
expectedValue = float64(hostInfo.BlocksProduced)
case "skipped":
expectedValue = float64(hostInfo.LeaderSlots - hostInfo.BlocksProduced)
}
// get labels (leaderSlotsByEpoch requires an extra one)
labels := []string{status, host}
if metric == leaderSlotsByEpoch {
labels = append(labels, fmt.Sprintf("%d", staticEpochInfo.Epoch))
}
// now we can do the assertion:
assert.Equalf(
t,
expectedValue,
testutil.ToFloat64(metric.WithLabelValues(labels...)),
"wrong value for block-production metric with labels: %s",
labels,
)
}
func assertSlotMetricsChangeCorrectly(t *testing.T, initial slotMetricValues, final slotMetricValues) {
// make sure that things have increased
assert.Greaterf(
t,
final.SlotHeight,
initial.SlotHeight,
"Slot has not increased! (%v -> %v)",
initial.SlotHeight,
final.SlotHeight,
)
assert.Greaterf(
t,
final.TotalTransactions,
initial.TotalTransactions,
"Total transactions have not increased! (%v -> %v)",
initial.TotalTransactions,
final.TotalTransactions,
)
assert.GreaterOrEqualf(
t,
final.EpochNumber,
initial.EpochNumber,
"Epoch number has decreased! (%v -> %v)",
initial.EpochNumber,
final.EpochNumber,
)
}
func TestSolanaCollector_WatchSlots_Static(t *testing.T) {
// reset metrics before running tests:
leaderSlotsTotal.Reset()
leaderSlotsByEpoch.Reset()
collector := createSolanaCollector(
&staticRPCClient{},
100*time.Millisecond,
)
prometheus.NewPedanticRegistry().MustRegister(collector)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go collector.WatchSlots(ctx)
time.Sleep(1 * time.Second)
firstSlot := staticEpochInfo.AbsoluteSlot - staticEpochInfo.SlotIndex
lastSlot := firstSlot + staticEpochInfo.SlotsInEpoch
tests := []struct {
expectedValue float64
metric prometheus.Gauge
}{
{expectedValue: float64(staticEpochInfo.AbsoluteSlot), metric: confirmedSlotHeight},
{expectedValue: float64(staticEpochInfo.TransactionCount), metric: totalTransactionsTotal},
{expectedValue: float64(staticEpochInfo.Epoch), metric: currentEpochNumber},
{expectedValue: float64(firstSlot), metric: epochFirstSlot},
{expectedValue: float64(lastSlot), metric: epochLastSlot},
}
for _, testCase := range tests {
name := extractName(testCase.metric.Desc())
t.Run(name, func(t *testing.T) {
assert.Equal(t, testCase.expectedValue, testutil.ToFloat64(testCase.metric))
})
}
metrics := map[string]*prometheus.CounterVec{
"solana_leader_slots_total": leaderSlotsTotal,
"solana_leader_slots_by_epoch": leaderSlotsByEpoch,
}
statuses := []string{"valid", "skipped"}
for name, metric := range metrics {
// subtest for each metric:
t.Run(name, func(t *testing.T) {
for _, status := range statuses {
// sub subtest for each status (as each one requires a different calc)
t.Run(status, func(t *testing.T) {
for _, identity := range identities {
testBlockProductionMetric(t, metric, identity, status)
}
})
}
})
}
}
func TestSolanaCollector_WatchSlots_Dynamic(t *testing.T) {
// reset metrics before running tests:
leaderSlotsTotal.Reset()
leaderSlotsByEpoch.Reset()
// create clients:
client := newDynamicRPCClient()
collector := createSolanaCollector(client, 300*time.Millisecond)
prometheus.NewPedanticRegistry().MustRegister(collector)
// start client/collector and wait a bit:
runCtx, runCancel := context.WithCancel(context.Background())
defer runCancel()
go client.Run(runCtx)
time.Sleep(time.Second)
slotsCtx, slotsCancel := context.WithCancel(context.Background())
defer slotsCancel()
go collector.WatchSlots(slotsCtx)
time.Sleep(time.Second)
initial := getSlotMetricValues()
// wait a bit:
var epochChanged bool
for i := 0; i < 5; i++ {
// wait a bit then get new metrics
time.Sleep(time.Second)
final := getSlotMetricValues()
// make sure things are changing correctly:
assertSlotMetricsChangeCorrectly(t, initial, final)
// sense check to make sure the exporter is not "ahead" of the client (due to double counting or whatever)
assert.LessOrEqualf(
t,
int(final.SlotHeight),
client.Slot,
"Exporter slot (%v) ahead of client slot (%v)!",
int(final.SlotHeight),
client.Slot,
)
assert.LessOrEqualf(
t,
int(final.TotalTransactions),
client.TransactionCount,
"Exporter transaction count (%v) ahead of client transaction count (%v)!",
int(final.TotalTransactions),
client.TransactionCount,
)
assert.LessOrEqualf(
t,
int(final.EpochNumber),
client.Epoch,
"Exporter epoch (%v) ahead of client epoch (%v)!",
int(final.EpochNumber),
client.Epoch,
)
// check if epoch changed
if final.EpochNumber > initial.EpochNumber {
epochChanged = true
}
// make current final the new initial (for next iteration)
initial = final
}
// epoch should have changed somewhere
assert.Truef(t, epochChanged, "Epoch has not changed!")
}

View File

@ -1,166 +0,0 @@
package main
import (
"context"
"fmt"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/assert"
"testing"
"time"
)
func TestSolanaCollector_Collect_Static(t *testing.T) {
collector := createSolanaCollector(
&staticRPCClient{},
slotPacerSchedule,
)
prometheus.NewPedanticRegistry().MustRegister(collector)
testCases := []collectionTest{
{
Name: "solana_active_validators",
ExpectedResponse: `
# HELP solana_active_validators Total number of active validators by state
# TYPE solana_active_validators gauge
solana_active_validators{state="current"} 2
solana_active_validators{state="delinquent"} 1
`,
},
{
Name: "solana_validator_activated_stake",
ExpectedResponse: `
# HELP solana_validator_activated_stake Activated stake per validator
# TYPE solana_validator_activated_stake gauge
solana_validator_activated_stake{nodekey="aaa",pubkey="AAA"} 49
solana_validator_activated_stake{nodekey="bbb",pubkey="BBB"} 42
solana_validator_activated_stake{nodekey="ccc",pubkey="CCC"} 43
`,
},
{
Name: "solana_validator_last_vote",
ExpectedResponse: `
# HELP solana_validator_last_vote Last voted slot per validator
# TYPE solana_validator_last_vote gauge
solana_validator_last_vote{nodekey="aaa",pubkey="AAA"} 92
solana_validator_last_vote{nodekey="bbb",pubkey="BBB"} 147
solana_validator_last_vote{nodekey="ccc",pubkey="CCC"} 148
`,
},
{
Name: "solana_validator_root_slot",
ExpectedResponse: `
# HELP solana_validator_root_slot Root slot per validator
# TYPE solana_validator_root_slot gauge
solana_validator_root_slot{nodekey="aaa",pubkey="AAA"} 3
solana_validator_root_slot{nodekey="bbb",pubkey="BBB"} 18
solana_validator_root_slot{nodekey="ccc",pubkey="CCC"} 19
`,
},
{
Name: "solana_validator_delinquent",
ExpectedResponse: `
# HELP solana_validator_delinquent Whether a validator is delinquent
# TYPE solana_validator_delinquent gauge
solana_validator_delinquent{nodekey="aaa",pubkey="AAA"} 1
solana_validator_delinquent{nodekey="bbb",pubkey="BBB"} 0
solana_validator_delinquent{nodekey="ccc",pubkey="CCC"} 0
`,
},
{
Name: "solana_node_version",
ExpectedResponse: `
# HELP solana_node_version Node version of solana
# TYPE solana_node_version gauge
solana_node_version{version="1.16.7"} 1
`,
},
}
runCollectionTests(t, collector, testCases)
}
func TestSolanaCollector_WatchSlots_Static(t *testing.T) {
// reset metrics before running tests:
leaderSlotsTotal.Reset()
leaderSlotsByEpoch.Reset()
collector := createSolanaCollector(
&staticRPCClient{},
100*time.Millisecond,
)
prometheus.NewPedanticRegistry().MustRegister(collector)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go collector.WatchSlots(ctx)
time.Sleep(1 * time.Second)
firstSlot := staticEpochInfo.AbsoluteSlot - staticEpochInfo.SlotIndex
lastSlot := firstSlot + staticEpochInfo.SlotsInEpoch
tests := []struct {
expectedValue float64
metric prometheus.Gauge
}{
{expectedValue: float64(staticEpochInfo.AbsoluteSlot), metric: confirmedSlotHeight},
{expectedValue: float64(staticEpochInfo.TransactionCount), metric: totalTransactionsTotal},
{expectedValue: float64(staticEpochInfo.Epoch), metric: currentEpochNumber},
{expectedValue: float64(firstSlot), metric: epochFirstSlot},
{expectedValue: float64(lastSlot), metric: epochLastSlot},
}
for _, testCase := range tests {
name := extractName(testCase.metric.Desc())
t.Run(name, func(t *testing.T) {
assert.Equal(t, testCase.expectedValue, testutil.ToFloat64(testCase.metric))
})
}
metrics := map[string]*prometheus.CounterVec{
"solana_leader_slots_total": leaderSlotsTotal,
"solana_leader_slots_by_epoch": leaderSlotsByEpoch,
}
statuses := []string{"valid", "skipped"}
for name, metric := range metrics {
// subtest for each metric:
t.Run(name, func(t *testing.T) {
for _, status := range statuses {
// sub subtest for each status (as each one requires a different calc)
t.Run(status, func(t *testing.T) {
for _, identity := range identities {
testBlockProductionMetric(t, metric, identity, status)
}
})
}
})
}
}
func testBlockProductionMetric(
t *testing.T,
metric *prometheus.CounterVec,
host string,
status string,
) {
hostInfo := staticBlockProduction.Hosts[host]
// get expected value depending on status:
var expectedValue float64
switch status {
case "valid":
expectedValue = float64(hostInfo.BlocksProduced)
case "skipped":
expectedValue = float64(hostInfo.LeaderSlots - hostInfo.BlocksProduced)
}
// get labels (leaderSlotsByEpoch requires an extra one)
labels := []string{status, host}
if metric == leaderSlotsByEpoch {
labels = append(labels, fmt.Sprintf("%d", staticEpochInfo.Epoch))
}
// now we can do the assertion:
assert.Equalf(
t,
expectedValue,
testutil.ToFloat64(metric.WithLabelValues(labels...)),
"wrong value for block-production metric with labels: %s",
labels,
)
}