moved tests into exporter_test and slots_test
This commit is contained in:
parent
81845a0b7d
commit
f834359575
|
@ -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,
|
||||
)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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!")
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue