Skip to content

Commit

Permalink
chore: add simple e2e tests script (kilnfi#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
MattKetmo authored Sep 28, 2023
1 parent c909000 commit 0845847
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 36 deletions.
47 changes: 37 additions & 10 deletions pkg/app/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"

"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

Expand All @@ -13,31 +14,57 @@ type Probe func() bool
var upProbe Probe = func() bool { return true }

type HTTPServer struct {
server *http.Server
*http.Server
}

func NewHTTPServer(addr string, readyFn Probe) *HTTPServer {
s := &HTTPServer{
server: &http.Server{Addr: addr},
type HTTPMuxOption func(*http.ServeMux)

func withProbe(path string, probe Probe) HTTPMuxOption {
return func(mux *http.ServeMux) {
mux.HandleFunc(path, probeHandler(probe))
}
}

func WithReadyProbe(probe Probe) HTTPMuxOption {
return withProbe("/ready", probe)
}

func WithLiveProbe(probe Probe) HTTPMuxOption {
return withProbe("/live", probe)
}

func WithMetrics(registry *prometheus.Registry) HTTPMuxOption {
return func(mux *http.ServeMux) {
mux.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
}
}

func NewHTTPServer(addr string, options ...HTTPMuxOption) *HTTPServer {
mux := http.NewServeMux()
server := &HTTPServer{
Server: &http.Server{
Addr: addr,
Handler: mux,
},
}

http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/ready", probeHandler(readyFn))
http.HandleFunc("/live", probeHandler(upProbe))
for _, option := range options {
option(mux)
}

return s
return server
}

func (s *HTTPServer) Run() error {
return s.listenAndServe()
}

func (s *HTTPServer) Shutdown(ctx context.Context) error {
return s.server.Shutdown(ctx)
return s.Server.Shutdown(ctx)
}

func (s *HTTPServer) listenAndServe() error {
err := s.server.ListenAndServe()
err := s.Server.ListenAndServe()

if err != nil && err != http.ErrServerClosed {
return fmt.Errorf("failed starting HTTP server: %w", err)
Expand Down
18 changes: 9 additions & 9 deletions pkg/app/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,16 +121,16 @@ func RunFunc(cCtx *cli.Context) error {
// HTTP server
//
log.Info().Msgf("starting HTTP server on %s", httpAddr)
readyFn := func() bool {
// ready when at least one watcher is ready
for _, node := range pool.Nodes {
if node.IsSynced() {
return true
}
}
return false
readyProbe := func() bool {
// ready when at least one watcher is synced
return pool.GetSyncedNode() != nil
}
httpServer := NewHTTPServer(httpAddr, readyFn)
httpServer := NewHTTPServer(
httpAddr,
WithReadyProbe(readyProbe),
WithLiveProbe(upProbe),
WithMetrics(metrics.Registry),
)
errg.Go(func() error {
return httpServer.Run()
})
Expand Down
37 changes: 20 additions & 17 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package metrics
import "github.com/prometheus/client_golang/prometheus"

type Metrics struct {
Registry *prometheus.Registry

// Global metrics
ActiveSet *prometheus.GaugeVec
BlockHeight *prometheus.GaugeVec
Expand All @@ -29,6 +31,7 @@ type Metrics struct {

func New(namespace string) *Metrics {
metrics := &Metrics{
Registry: prometheus.NewRegistry(),
BlockHeight: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Namespace: namespace,
Expand Down Expand Up @@ -171,21 +174,21 @@ func New(namespace string) *Metrics {
}

func (m *Metrics) Register() {
prometheus.MustRegister(m.BlockHeight)
prometheus.MustRegister(m.ActiveSet)
prometheus.MustRegister(m.SeatPrice)
prometheus.MustRegister(m.Rank)
prometheus.MustRegister(m.ValidatedBlocks)
prometheus.MustRegister(m.MissedBlocks)
prometheus.MustRegister(m.SoloMissedBlocks)
prometheus.MustRegister(m.TrackedBlocks)
prometheus.MustRegister(m.SkippedBlocks)
prometheus.MustRegister(m.Tokens)
prometheus.MustRegister(m.IsBonded)
prometheus.MustRegister(m.IsJailed)
prometheus.MustRegister(m.Vote)
prometheus.MustRegister(m.NodeBlockHeight)
prometheus.MustRegister(m.NodeSynced)
prometheus.MustRegister(m.UpgradePlan)
prometheus.MustRegister(m.ProposalEndTime)
m.Registry.MustRegister(m.BlockHeight)
m.Registry.MustRegister(m.ActiveSet)
m.Registry.MustRegister(m.SeatPrice)
m.Registry.MustRegister(m.Rank)
m.Registry.MustRegister(m.ValidatedBlocks)
m.Registry.MustRegister(m.MissedBlocks)
m.Registry.MustRegister(m.SoloMissedBlocks)
m.Registry.MustRegister(m.TrackedBlocks)
m.Registry.MustRegister(m.SkippedBlocks)
m.Registry.MustRegister(m.Tokens)
m.Registry.MustRegister(m.IsBonded)
m.Registry.MustRegister(m.IsJailed)
m.Registry.MustRegister(m.Vote)
m.Registry.MustRegister(m.NodeBlockHeight)
m.Registry.MustRegister(m.NodeSynced)
m.Registry.MustRegister(m.UpgradePlan)
m.Registry.MustRegister(m.ProposalEndTime)
}
98 changes: 98 additions & 0 deletions tests/e2e.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package main

import (
"context"
"errors"
"fmt"
"io"
"net/http"
"strings"
"time"

"github.com/kilnfi/cosmos-validator-watcher/pkg/app"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
"golang.org/x/sync/errgroup"
)

var data = []struct {
node string
validator string
}{
{"https://cosmos-rpc.publicnode.com:443", "3DC4DD610817606AD4A8F9D762A068A81E8741E2"},
{"https://evmos-rpc.publicnode.com:443", "C28576ECA1802CD7046913848784D8147F6BAB22"},
{"https://injective-rpc.publicnode.com:443", "37CE71AD8CD4DC01D8798E103A70978591708169"},
{"https://juno-rpc.publicnode.com:443", "C55563E7FAD03561899AC6638E3E1E07DCB68D99"},
{"https://kava-rpc.publicnode.com:443", "C669FD6A91DD9771BCEAE988E2C58356E8B33383"},
// {"https://neutron-rpc.publicnode.com:443", "D2C7578217BA3ACEE64120FBCABD1B47EA51F9CE"},
{"https://osmosis-rpc.publicnode.com:443", "17386B308EF9670CDD412FB2F3C09C5B875FB8B8"},
{"https://persistence-rpc.publicnode.com:443", "C016A67FFD0E91FF9F0A81CF639F05B9161D90C8"},
{"https://quicksilver-rpc.publicnode.com:443", "72A46AB01C191843223BF54B29201D87D7CEC44E"},
{"https://stride-rpc.publicnode.com:443", "6F5D7AB6943BE2D01DD910CCD7B06D9E30A0FEFF"},
{"https://rpc-sei-ia.cosmosia.notional.ventures:443", "908A25DA02880FAA7C1BE016A5ABFD165D9D9087"},
}

func main() {
ctx := context.Background()

app := &cli.App{
Name: "cosmos-validator-watcher",
Flags: app.Flags,
Action: app.RunFunc,
}

for _, d := range data {
args := []string{
"cosmos-validator-watcher",
"--node", d.node,
"--validator", d.validator,
}

// Allow 3 seconds timeout
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()

errg, ctx := errgroup.WithContext(ctx)
errg.Go(func() error {
return app.RunContext(ctx, args)
})
errg.Go(func() error {
time.Sleep(1500 * time.Millisecond)
return checkMetrics(ctx)
})

if err := errg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
log.Fatal().Err(err).Msg("")
}
}
}

// checkMetrics ensures if the given metric is present
func checkMetrics(ctx context.Context) error {
metric := "cosmos_validator_watcher_block_height"

req, err := http.NewRequestWithContext(ctx, "GET", "http://localhost:8080/metrics", nil)
if err != nil {
return fmt.Errorf("error creating request: %w", err)
}

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error sending request: %w", err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("error reading response body: %w", err)
}

if !strings.Contains(string(body), metric) {
return fmt.Errorf("metric '%s' is not present", metric)
}

log.Info().Msg("metrics are present")

return nil
}

0 comments on commit 0845847

Please sign in to comment.