Skip to content

Commit

Permalink
feat: add app test (#71)
Browse files Browse the repository at this point in the history
* feat: add app test

* chore: not ignore assets

* Update pkg/app.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update pkg/app_test.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* chore: add cmd test

* chore: add readme badge

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
freak12techno and coderabbitai[bot] authored Jun 28, 2024
1 parent 87241cf commit ce2df06
Show file tree
Hide file tree
Showing 14 changed files with 426 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
main
config*.toml
!assets/config*.toml
cosmos-validators-exporter
.idea/
dist/
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

![Latest release](https://img.shields.io/github/v/release/QuokkaStake/cosmos-validators-exporter)
[![Actions Status](https://github.com/QuokkaStake/cosmos-validators-exporter/workflows/test/badge.svg)](https://github.com/QuokkaStake/cosmos-validators-exporter/actions)
[![codecov](https://codecov.io/gh/QuokkaStake/cosmos-validators-exporter/graph/badge.svg?token=WALLM02IEC)](https://codecov.io/gh/QuokkaStake/cosmos-validators-exporter)

cosmos-validators-exporter is a Prometheus scraper that fetches validators stats from an LCD server
exposed by a fullnode.
Expand Down
11 changes: 11 additions & 0 deletions assets/config-invalid-listen-address.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
listen-address = "invalid"

[[chains]]
name = "sentinel"
lcd-endpoint = "https://api.sentinel.quokkastake.io"
coingecko-currency = "sentinel"
base-denom = "udvpn"
bech-wallet-prefix = "sent"
validators = [
{ address = "sentvaloper1rw9wtyhsus7jvx55v3qv5nzun054ma6kz4237k" }
]
1 change: 0 additions & 1 deletion assets/valid.toml → assets/config-invalid.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[[chains]]
name = "sentinel"
lcd-endpoint = "https://api.sentinel.quokkastake.io"
coingecko-currency = "sentinel"
base-denom = "udvpn"
Expand Down
39 changes: 39 additions & 0 deletions assets/config-valid.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[log]
level = "debug"

[[chains]]
name = "cosmos"
lcd-endpoint = "https://api.cosmos.quokkastake.io"
bech-wallet-prefix = "cosmos"
validators = [
{ address = "cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e", consensus-address = "cosmosvalcons1rt4g447zhv6jcqwdl447y88guwm0eevnrelgzc" }
]
base-denom = "uatom"
is-provider = true
denoms = [
{ denom = "uatom", display-denom = "atom", coingecko-currency = "cosmos" },
{ denom = "ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5", display-denom = "ntrn", coingecko-currency = "neutron" },
{ denom = "ibc/6B8A3F5C2AD51CD6171FA41A7E8C35AD594AB69226438DB94450436EA57B3A89", display-denom = "strd", coingecko-currency = "stride" },
{ denom = "ibc/054892D6BB43AF8B93AAC28AA5FD7019D2C59A15DAFD6F45C1FA2BF9BDA22454", display-denom = "stosmo", coingecko-currency = "osmosis" },
{ denom = "ibc/5CAE744C89BC70AE7B38019A1EDF83199B7E10F00F160E7F4F12BCA7A32A7EE5", display-denom = "stluna", coingecko-currency = "terra-luna-2" },
{ denom = "ibc/715BD634CF4D914C3EE93B0F8A9D2514B743F6FE36BC80263D1BC5EE4B3C5D40", display-denom = "ststars", coingecko-currency = "stargaze" },
{ denom = "ibc/88DCAA43A9CD099E1F9BBB80B9A90F64782EBA115A84B2CD8398757ADA4F4B40", display-denom = "stjuno", coingecko-currency = "juno-network" },
{ denom = "ibc/A4D99E716D91A579AC3A9684AAB7B5CB0A0861DD3DD942901D970EDB6787860E", display-denom = "stsomm", coingecko-currency = "sommelier" },
{ denom = "ibc/B011C1A0AD5E717F674BA59FD8E05B2F946E4FD41C9CB3311C95F7ED4B815620", display-denom = "stinj", denom-coefficient = 1000000000000000000, coingecko-currency = "injective-protocol" },
{ denom = "ibc/B05539B66B72E2739B986B86391E5D08F12B8D5D2C2A7F8F8CF9ADF674DFA231", display-denom = "statom", coingecko-currency = "cosmos" },
{ denom = "ibc/B38AAA0F7A3EC4D7C8E12DFA33FF93205FE7A42738A4B0590E2FF15BC60A612B", display-denom = "stevmos", denom-coefficient = 1000000000000000000, coingecko-currency = "evmos" },
{ denom = "ibc/D41ECC8FEF1B7E9C4BCC58B1362588420853A9D0B898EDD513D9B79AFFA195C8", display-denom = "stumee", coingecko-currency = "umee" },
{ denom = "ibc/E92E07E68705FAD13305EE9C73684B30A7B66A52F54C9890327E0A4C0F1D22E3", display-denom = "stcmdx", coingecko-currency = "comdex" },
]

[[chains.consumers]]
name = "neutron"
lcd-endpoint = "https://api.neutron.quokkastake.io"
chain-id = "neutron-1"
base-denom = "untrn"
bech-wallet-prefix = "neutron"
bech-validator-prefix = "neutronvaloper"
bech-consensus-prefix = "neutronvalcons"
denoms = [
{ denom = "untrn", display-denom = "ntrn", coingecko-currency = "neutron" }
]
11 changes: 11 additions & 0 deletions assets/config-with-warnings.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[chains]]
name = "sentinel"
lcd-endpoint = "https://api.sentinel.quokkastake.io"
base-denom = "udvpn"
bech-wallet-prefix = "sent"
denoms = [
{ denom = "udvpn", display-denom = "dvpn" }
]
validators = [
{ address = "sentvaloper1rw9wtyhsus7jvx55v3qv5nzun054ma6kz4237k" }
]
14 changes: 5 additions & 9 deletions cmd/cosmos-validators-exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ func ExecuteValidateConfig(configPath string) {
filesystem := &OsFS{}
config, err := configPkg.GetConfig(configPath, filesystem)
if err != nil {
logger.GetDefaultLogger().Fatal().Err(err).Msg("Could not load config!")
logger.GetDefaultLogger().Panic().Err(err).Msg("Could not load config!")
}

if err := config.Validate(); err != nil {
logger.GetDefaultLogger().Fatal().Err(err).Msg("Config is invalid!")
logger.GetDefaultLogger().Panic().Err(err).Msg("Config is invalid!")
}

warnings := config.DisplayWarnings()
Expand Down Expand Up @@ -73,18 +73,14 @@ func main() {
}

rootCmd.PersistentFlags().StringVar(&ConfigPath, "config", "", "Config file path")
if err := rootCmd.MarkPersistentFlagRequired("config"); err != nil {
logger.GetDefaultLogger().Fatal().Err(err).Msg("Could not set flag as required")
}
_ = rootCmd.MarkPersistentFlagRequired("config")

validateConfigCmd.PersistentFlags().StringVar(&ConfigPath, "config", "", "Config file path")
if err := validateConfigCmd.MarkPersistentFlagRequired("config"); err != nil {
logger.GetDefaultLogger().Fatal().Err(err).Msg("Could not set flag as required")
}
_ = validateConfigCmd.MarkPersistentFlagRequired("config")

rootCmd.AddCommand(validateConfigCmd)

if err := rootCmd.Execute(); err != nil {
logger.GetDefaultLogger().Fatal().Err(err).Msg("Could not start application")
logger.GetDefaultLogger().Panic().Err(err).Msg("Could not start application")
}
}
88 changes: 88 additions & 0 deletions cmd/cosmos-validators-exporter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

//nolint:paralleltest // disabled
func TestValidateConfigNoConfigProvided(t *testing.T) {
defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

os.Args = []string{"cmd", "validate-config"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestValidateConfigFailedToLoad(t *testing.T) {
defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

os.Args = []string{"cmd", "validate-config", "--config", "../assets/config-not-found.toml"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestValidateConfigInvalid(t *testing.T) {
defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

os.Args = []string{"cmd", "validate-config", "--config", "../assets/config-invalid.toml"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestValidateConfigWithWarnings(t *testing.T) {
os.Args = []string{"cmd", "validate-config", "--config", "../assets/config-with-warnings.toml"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestValidateConfigValid(t *testing.T) {
os.Args = []string{"cmd", "validate-config", "--config", "../assets/config-valid.toml"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestStartNoConfigProvided(t *testing.T) {
defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

os.Args = []string{"cmd"}
main()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestStartConfigProvided(t *testing.T) {
defer func() {
if r := recover(); r == nil {
require.Fail(t, "Expected to have a panic here!")
}
}()

os.Args = []string{"cmd", "--config", "../assets/config-invalid.toml"}
main()
assert.True(t, true)
}
36 changes: 26 additions & 10 deletions pkg/app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pkg

import (
"context"
fetchersPkg "main/pkg/fetchers"
"main/pkg/fs"
generatorsPkg "main/pkg/generators"
Expand Down Expand Up @@ -30,6 +31,7 @@ type App struct {
Tracer trace.Tracer
Config *config.Config
Logger *zerolog.Logger
Server *http.Server

RPCs map[string]*tendermint.RPCWithConsumers

Expand All @@ -48,11 +50,11 @@ type App struct {
func NewApp(configPath string, filesystem fs.FS, version string) *App {
appConfig, err := config.GetConfig(configPath, filesystem)
if err != nil {
loggerPkg.GetDefaultLogger().Fatal().Err(err).Msg("Could not load config")
loggerPkg.GetDefaultLogger().Panic().Err(err).Msg("Could not load config")
}

if err = appConfig.Validate(); err != nil {
loggerPkg.GetDefaultLogger().Fatal().Err(err).Msg("Provided config is invalid!")
loggerPkg.GetDefaultLogger().Panic().Err(err).Msg("Provided config is invalid!")
}

logger := loggerPkg.GetLogger(appConfig.LogConfig)
Expand All @@ -66,11 +68,7 @@ func NewApp(configPath string, filesystem fs.FS, version string) *App {
entry.Msg(warning.Message)
}

tracer, err := tracing.InitTracer(appConfig.TracingConfig, version)
if err != nil {
loggerPkg.GetDefaultLogger().Fatal().Err(err).Msg("Error setting up tracing")
}

tracer := tracing.InitTracer(appConfig.TracingConfig, version)
coingecko := coingeckoPkg.NewCoingecko(appConfig, logger, tracer)

rpcs := make(map[string]*tendermint.RPCWithConsumers, len(appConfig.Chains))
Expand Down Expand Up @@ -124,27 +122,41 @@ func NewApp(configPath string, filesystem fs.FS, version string) *App {
generatorsPkg.NewValidatorCommissionRateGenerator(appConfig.Chains, logger),
}

server := &http.Server{Addr: appConfig.ListenAddress, Handler: nil}

return &App{
Logger: logger,
Config: appConfig,
Tracer: tracer,
RPCs: rpcs,
Fetchers: fetchers,
Generators: generators,
Server: server,
}
}

func (a *App) Start() {
otelHandler := otelhttp.NewHandler(http.HandlerFunc(a.Handler), "prometheus")
http.Handle("/metrics", otelHandler)
handler := http.NewServeMux()
handler.Handle("/metrics", otelHandler)
handler.HandleFunc("/healthcheck", a.Healthcheck)
a.Server.Handler = handler

a.Logger.Info().Str("addr", a.Config.ListenAddress).Msg("Listening")
err := http.ListenAndServe(a.Config.ListenAddress, nil)

err := a.Server.ListenAndServe()
if err != nil {
a.Logger.Fatal().Err(err).Msg("Could not start application")
a.Logger.Panic().Err(err).Msg("Could not start application")
}
}

func (a *App) Stop() {
a.Logger.Info().Str("addr", a.Config.ListenAddress).Msg("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_ = a.Server.Shutdown(ctx)
}

func (a *App) Handler(w http.ResponseWriter, r *http.Request) {
requestID := uuid.New().String()

Expand Down Expand Up @@ -209,3 +221,7 @@ func (a *App) Handler(w http.ResponseWriter, r *http.Request) {
Float64("request-time", time.Since(requestStart).Seconds()).
Msg("Request processed")
}

func (a *App) Healthcheck(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("ok"))
}
Loading

0 comments on commit ce2df06

Please sign in to comment.