Skip to content

Commit

Permalink
feat: add app test
Browse files Browse the repository at this point in the history
  • Loading branch information
freak12techno committed Jun 28, 2024
1 parent 87241cf commit f2804df
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 44 deletions.
10 changes: 0 additions & 10 deletions assets/valid.toml

This file was deleted.

34 changes: 24 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,39 @@ 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...")
_ = a.Server.Shutdown(context.Background())
}

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

Expand Down Expand Up @@ -209,3 +219,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"))
}
232 changes: 232 additions & 0 deletions pkg/app_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
package pkg

import (
"io"
"main/assets"
"main/pkg/fs"
"net/http"
"testing"
"time"

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

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

filesystem := &fs.TestFS{}

app := NewApp("not-found-config.toml", filesystem, "1.2.3")
app.Start()
}

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

filesystem := &fs.TestFS{}

app := NewApp("config-invalid.toml", filesystem, "1.2.3")
app.Start()
}

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

filesystem := &fs.TestFS{}

app := NewApp("config-invalid-listen-address.toml", filesystem, "1.2.3")
app.Start()
}

//nolint:paralleltest // disabled
func TestAppFailToStop(t *testing.T) {
filesystem := &fs.TestFS{}

app := NewApp("config-valid.toml", filesystem, "1.2.3")
app.Stop()
assert.True(t, true)
}

//nolint:paralleltest // disabled
func TestAppLoadConfigOk(t *testing.T) {
filesystem := &fs.TestFS{}

app := NewApp("config-valid.toml", filesystem, "1.2.3")
go app.Start()

for {
request, err := http.Get("http://localhost:9560/healthcheck")
_ = request.Body.Close()
if err == nil {
break
}

time.Sleep(time.Millisecond * 100)
}

httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/staking/v1beta1/validators?pagination.count_total=true&pagination.limit=1000",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("validators.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/slashing/v1beta1/signing_infos/cosmosvalcons1rt4g447zhv6jcqwdl447y88guwm0eevnrelgzc",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("signing-info.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.neutron.quokkastake.io/cosmos/slashing/v1beta1/signing_infos/neutronvalcons1w426hkttrwrve9mj77ld67lzgx5u9m8plhmwc6",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("signing-info.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/staking/v1beta1/params",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("staking-params.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/slashing/v1beta1/params",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("slashing-params.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.neutron.quokkastake.io/cosmos/slashing/v1beta1/params",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("slashing-params.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/staking/v1beta1/validators/cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e/unbonding_delegations?pagination.count_total=true&pagination.limit=1",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("unbonds.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/staking/v1beta1/validators/cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e/delegations/cosmos1xqz9pemz5e5zycaa89kys5aw6m8rhgsvtp9lt2",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("self-delegation.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/distribution/v1beta1/validators/cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e/commission",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("commission.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/interchain_security/ccv/provider/consumer_validators/neutron-1",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("consumer-validators.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/distribution/v1beta1/delegators/cosmos1xqz9pemz5e5zycaa89kys5aw6m8rhgsvtp9lt2/rewards/cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("rewards.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/staking/v1beta1/validators/cosmosvaloper1xqz9pemz5e5zycaa89kys5aw6m8rhgsvw4328e/delegations?pagination.count_total=true&pagination.limit=1",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("delegations.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/bank/v1beta1/balances/cosmos1xqz9pemz5e5zycaa89kys5aw6m8rhgsvtp9lt2",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("balances.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/cosmos/base/tendermint/v1beta1/node_info",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("node-info.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.neutron.quokkastake.io/cosmos/base/tendermint/v1beta1/node_info",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("node-info.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.neutron.quokkastake.io/cosmos/params/v1beta1/params?subspace=ccvconsumer&key=SoftOptOutThreshold",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("soft-opt-out-threshold.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.neutron.quokkastake.io/cosmos/bank/v1beta1/balances/neutron1xqz9pemz5e5zycaa89kys5aw6m8rhgsv07va3d",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("balances.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/interchain_security/ccv/provider/validator_consumer_addr?chain_id=neutron-1&provider_address=cosmosvalcons1rt4g447zhv6jcqwdl447y88guwm0eevnrelgzc",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("assigned-key.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/interchain_security/ccv/provider/consumer_chains_per_validator/cosmosvalcons1rt4g447zhv6jcqwdl447y88guwm0eevnrelgzc",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("validator-consumers.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/interchain_security/ccv/provider/consumer_commission_rate/neutron-1/cosmosvalcons1rt4g447zhv6jcqwdl447y88guwm0eevnrelgzc",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("consumer-commission.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.cosmos.quokkastake.io/interchain_security/ccv/provider/consumer_chains",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("consumer-info.json")),
)

httpmock.RegisterResponder(
"GET",
"https://api.coingecko.com/api/v3/simple/price?ids=cosmos,neutron,stride,osmosis,terra-luna-2,stargaze,juno-network,sommelier,injective-protocol,cosmos,evmos,umee,comdex,neutron&vs_currencies=usd",
httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("coingecko.json")),
)

httpmock.RegisterResponder("GET", "http://localhost:9560/healthcheck", httpmock.InitialTransport.RoundTrip)
httpmock.RegisterResponder("GET", "http://localhost:9560/metrics", httpmock.InitialTransport.RoundTrip)

response, err := http.Get("http://localhost:9560/metrics")
require.NoError(t, err)
require.NotEmpty(t, response)

body, err := io.ReadAll(response.Body)
require.NoError(t, err)
require.NotEmpty(t, body)

err = response.Body.Close()
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func TestLoadConfigValid(t *testing.T) {
t.Parallel()

filesystem := &fs.TestFS{}
config, err := GetConfig("valid.toml", filesystem)
config, err := GetConfig("config-valid.toml", filesystem)
require.NoError(t, err)
require.NotNil(t, config)
}
File renamed without changes.
18 changes: 7 additions & 11 deletions pkg/tracing/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package tracing
import (
"context"
"encoding/base64"
"fmt"
configPkg "main/pkg/config"

"go.opentelemetry.io/otel"
Expand All @@ -12,7 +11,7 @@ import (
"go.opentelemetry.io/otel/trace"
)

func getExporter(config configPkg.TracingConfig) (tracesdk.SpanExporter, error) {
func getExporter(config configPkg.TracingConfig) tracesdk.SpanExporter {
if config.Enabled.Bool {
opts := []otlptracehttp.Option{
otlptracehttp.WithEndpoint(config.OpenTelemetryHTTPHost),
Expand All @@ -30,25 +29,22 @@ func getExporter(config configPkg.TracingConfig) (tracesdk.SpanExporter, error)
}))
}

return otlptracehttp.New(
exporter, _ := otlptracehttp.New(
context.Background(),
opts...,
)
return exporter
}

return NewNoopExporter(), nil
return NewNoopExporter()
}

func InitTracer(config configPkg.TracingConfig, version string) (trace.Tracer, error) {
exporter, err := getExporter(config)
if err != nil {
return nil, fmt.Errorf("error creating exporter: %w", err)
}

func InitTracer(config configPkg.TracingConfig, version string) trace.Tracer {
exporter := getExporter(config)
tp := NewTraceProvider(exporter, version)
otel.SetTracerProvider(tp)

return tp.Tracer("main"), nil
return tp.Tracer("main")
}

func InitNoopTracer() trace.Tracer {
Expand Down
Loading

0 comments on commit f2804df

Please sign in to comment.