diff --git a/Makefile b/Makefile index e091c00..1124d33 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,11 @@ lint: golangci-lint run --fix ./... test: + go test -coverpkg=./... -coverprofile cover.out ./... + +test-verbose: go test -coverpkg=./... -coverprofile cover.out -v ./... + coverage: go tool cover -html=cover.out diff --git a/assets/commission.json b/assets/commission.json new file mode 100644 index 0000000..f26ddc6 --- /dev/null +++ b/assets/commission.json @@ -0,0 +1,10 @@ +{ + "commission": { + "commission": [ + { + "denom": "uatom", + "amount": "12345" + } + ] + } +} \ No newline at end of file diff --git a/assets/cosmos-directory.json b/assets/cosmos-directory.json new file mode 100644 index 0000000..7655833 --- /dev/null +++ b/assets/cosmos-directory.json @@ -0,0 +1,104 @@ +{ + "repository": { + "url": "https://github.com/cosmos/chain-registry", + "branch": "master", + "commit": "c6cfe11be261b20ce5881ea9ba38d855130c22a5", + "timestamp": 1720810736 + }, + "chains": [ + { + "name": "8ball", + "path": "8ball", + "chain_name": "8ball", + "network_type": "mainnet", + "pretty_name": "8ball", + "chain_id": "eightball-1", + "status": "live", + "bech32_prefix": "8ball", + "slip44": 118, + "symbol": "EBL", + "display": "ebl", + "denom": "uebl", + "decimals": 6, + "image": "https://raw.githubusercontent.com/cosmos/chain-registry/master/8ball/images/8ball.svg", + "website": "https://8ball.info/", + "height": null, + "best_apis": { + "rest": [], + "rpc": [] + }, + "proxy_status": { + "rest": false, + "rpc": false + }, + "versions": { + "application_version": "v1", + "cosmos_sdk_version": "0.46.7" + }, + "cosmwasm_enabled": true, + "explorers": [ + { + "url": "https://explorer.8ball.info/", + "tx_page": "https://explorer.8ball.info/8ball/tx/${txHash}" + }, + { + "kind": "ping.pub", + "url": "https://ping.pub/8ball", + "tx_page": "https://ping.pub/8ball/tx/${txHash}" + }, + { + "kind": "NodeStake Explorer", + "url": "https://explorer.nodestake.top/8ball/", + "tx_page": "https://explorer.nodestake.top/8ball/tx/${txHash}" + }, + { + "kind": "TC Network", + "url": "https://explorer.tcnetwork.io/8ball", + "tx_page": "https://explorer.tcnetwork.io/8ball/transaction/${txHash}" + }, + { + "kind": "TC Network", + "url": "https://explorer.co.id/8ball", + "tx_page": "https://explorer.co.id/8ball/tx/${txHash}" + }, + { + "kind": "NODEXPLORER", + "url": "https://explorer.nodexcapital.com/8ball", + "tx_page": "https://explorer.nodexcapital.com/8ball/tx/${txHash}" + } + ], + "assets": [ + { + "name": "8ball", + "description": "The native staking token of 8ball.", + "symbol": "EBL", + "denom": "uebl", + "decimals": 6, + "base": { + "denom": "uebl", + "exponent": 0 + }, + "display": { + "denom": "ebl", + "exponent": 6 + }, + "denom_units": [ + { + "denom": "uebl", + "exponent": 0 + }, + { + "denom": "ebl", + "exponent": 6 + } + ], + "logo_URIs": { + "png": "https://raw.githubusercontent.com/cosmos/chain-registry/master/8ball/images/8ball.png", + "svg": "https://raw.githubusercontent.com/cosmos/chain-registry/master/8ball/images/8ball.svg" + }, + "image": "https://raw.githubusercontent.com/cosmos/chain-registry/master/8ball/images/8ball.svg" + } + ] + } + ] +} \ No newline at end of file diff --git a/assets/denom-trace.json b/assets/denom-trace.json new file mode 100644 index 0000000..a65a6b0 --- /dev/null +++ b/assets/denom-trace.json @@ -0,0 +1,6 @@ +{ + "denom_trace": { + "path": "transfer/channel-569", + "base_denom": "untrn" + } +} \ No newline at end of file diff --git a/pkg/alias_manager/alias_manager_test.go b/pkg/alias_manager/alias_manager_test.go index 157d4e0..ac0802e 100644 --- a/pkg/alias_manager/alias_manager_test.go +++ b/pkg/alias_manager/alias_manager_test.go @@ -1,8 +1,6 @@ package alias_manager_test import ( - "errors" - "main/assets" "main/pkg/alias_manager" configPkg "main/pkg/config" configTypes "main/pkg/config/types" @@ -13,60 +11,14 @@ import ( "github.com/stretchr/testify/require" ) -type MockFile struct { - FailWrite bool - FailClose bool -} - -func (file *MockFile) Write(p []byte) (int, error) { - if file.FailWrite { - return 1, errors.New("not yet supported") - } - - return len(p), nil -} - -func (file *MockFile) Close() error { - if file.FailClose { - return errors.New("not yet supported") - } - - return nil -} - -type MockAliasesFS struct { - FailCreate bool - FailWrite bool - FailClose bool -} - -func (filesystem *MockAliasesFS) ReadFile(name string) ([]byte, error) { - return assets.EmbedFS.ReadFile(name) -} - -func (filesystem *MockAliasesFS) Create(path string) (fs.File, error) { - if filesystem.FailCreate { - return nil, errors.New("not yet supported") - } - - return &MockFile{ - FailWrite: filesystem.FailWrite, - FailClose: filesystem.FailClose, - }, nil -} - -func (filesystem *MockAliasesFS) Write(p []byte) (int, error) { - return 0, errors.New("not yet supported") -} - func TestAliasManagerEnabled(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "path", } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) require.True(t, aliasManager.Enabled()) } @@ -74,9 +26,9 @@ func TestAliasManagerEnabled(t *testing.T) { func TestAliasManagerLoadDisabled(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) aliasManager.Load() require.Empty(t, aliasManager.Aliases) @@ -85,9 +37,9 @@ func TestAliasManagerLoadDisabled(t *testing.T) { func TestAliasManagerLoadFailed(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{AliasesPath: "nonexistent.toml"} - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) aliasManager.Load() require.Empty(t, aliasManager.Aliases) @@ -96,9 +48,9 @@ func TestAliasManagerLoadFailed(t *testing.T) { func TestAliasManagerLoadInvalidToml(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{AliasesPath: "invalid-toml.toml"} - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) aliasManager.Load() require.Empty(t, aliasManager.Aliases) @@ -107,14 +59,14 @@ func TestAliasManagerLoadInvalidToml(t *testing.T) { func TestAliasManagerLoadSuccess(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "valid-aliases.toml", Chains: configTypes.Chains{ {Name: "chain"}, }, } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) aliasManager.Load() require.NotEmpty(t, aliasManager.Aliases) @@ -124,9 +76,9 @@ func TestAliasManagerLoadSuccess(t *testing.T) { func TestAliasManagerSaveDisabled(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Save() require.NoError(t, err) @@ -135,9 +87,9 @@ func TestAliasManagerSaveDisabled(t *testing.T) { func TestAliasManagerSaveErrorOpening(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{AliasesPath: "savefile.toml"} - filesystem := &MockAliasesFS{FailCreate: true} + filesystem := &fs.MockFs{FailCreate: true} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Save() require.Error(t, err) @@ -146,19 +98,19 @@ func TestAliasManagerSaveErrorOpening(t *testing.T) { func TestAliasManagerSaveErrorWriting(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "savefile.toml", Chains: configTypes.Chains{ {Name: "chain"}, }, } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Set("subscription", "chain", "wallet", "alias") require.NoError(t, err) - aliasManager.FS = &MockAliasesFS{FailWrite: true} + aliasManager.FS = &fs.MockFs{FailWrite: true} err = aliasManager.Save() require.Error(t, err) } @@ -166,19 +118,19 @@ func TestAliasManagerSaveErrorWriting(t *testing.T) { func TestAliasManagerSaveErrorClosing(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "savefile.toml", Chains: configTypes.Chains{ {Name: "chain"}, }, } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Set("subscription", "chain", "wallet", "alias") require.NoError(t, err) - aliasManager.FS = &MockAliasesFS{FailClose: true} + aliasManager.FS = &fs.MockFs{FailClose: true} err = aliasManager.Save() require.Error(t, err) } @@ -186,9 +138,9 @@ func TestAliasManagerSaveErrorClosing(t *testing.T) { func TestAliasManagerSetDisabled(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Set("subscription", "chain", "wallet", "alias") require.NoError(t, err) @@ -203,12 +155,12 @@ func TestAliasManagerSetNoChain(t *testing.T) { } }() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "savefile.toml", Chains: configTypes.Chains{}, } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) _ = aliasManager.Set("subscription", "chain", "wallet", "alias") } @@ -216,14 +168,14 @@ func TestAliasManagerSetNoChain(t *testing.T) { func TestAliasManagerGetLinks(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{ AliasesPath: "savefile.toml", Chains: configTypes.Chains{ {Name: "chain"}, }, } - filesystem := &MockAliasesFS{} + filesystem := &fs.MockFs{} aliasManager := alias_manager.NewAliasManager(logger, config, filesystem) err := aliasManager.Set("subscription", "chain", "wallet", "alias") require.NoError(t, err) diff --git a/pkg/alias_manager/toml_types_test.go b/pkg/alias_manager/toml_types_test.go index 10d6d25..0680f52 100644 --- a/pkg/alias_manager/toml_types_test.go +++ b/pkg/alias_manager/toml_types_test.go @@ -20,7 +20,7 @@ func TestToAliasesValid(t *testing.T) { }, } - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chains := configTypes.Chains{ {Name: "chain"}, } @@ -47,7 +47,7 @@ func TestToAliasesNoChain(t *testing.T) { }, } - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chains := configTypes.Chains{} defer func() { diff --git a/pkg/converter/converter_test.go b/pkg/converter/converter_test.go index 387396c..9fa346f 100644 --- a/pkg/converter/converter_test.go +++ b/pkg/converter/converter_test.go @@ -21,7 +21,7 @@ import ( func TestConverterTxError(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -42,7 +42,7 @@ func TestConverterTxError(t *testing.T) { func TestConverterParseError(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -57,7 +57,7 @@ func TestConverterParseError(t *testing.T) { func TestConverterEmptyEvent(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -71,7 +71,7 @@ func TestConverterEmptyEvent(t *testing.T) { func TestConverterErrorConvert(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -85,7 +85,7 @@ func TestConverterErrorConvert(t *testing.T) { func TestConverterErrorUnmarshal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -100,7 +100,7 @@ func TestConverterErrorUnmarshal(t *testing.T) { func TestConverterOkUnmarshal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -115,7 +115,7 @@ func TestConverterOkUnmarshal(t *testing.T) { func TestConverterUnsupportedMessage(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -128,7 +128,7 @@ func TestConverterUnsupportedMessage(t *testing.T) { func TestConverterUnparsedMessage(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -144,7 +144,7 @@ func TestConverterUnparsedMessage(t *testing.T) { func TestConverterParsedCorrectly(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -164,7 +164,7 @@ func TestConverterParsedCorrectly(t *testing.T) { func TestConverterParsedInternal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) @@ -197,7 +197,7 @@ func TestConverterParsedInternal(t *testing.T) { func TestConverterAllMessageSkipped(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() chain := &configTypes.Chain{Name: "chain"} converter := converterPkg.NewConverter(logger, chain) diff --git a/pkg/data_fetcher/fetch_commission_test.go b/pkg/data_fetcher/fetch_commission_test.go new file mode 100644 index 0000000..658ffa8 --- /dev/null +++ b/pkg/data_fetcher/fetch_commission_test.go @@ -0,0 +1,120 @@ +package data_fetcher + +import ( + "main/assets" + aliasManagerPkg "main/pkg/alias_manager" + configPkg "main/pkg/config" + "main/pkg/config/types" + "main/pkg/fs" + loggerPkg "main/pkg/logger" + "main/pkg/metrics" + "main/pkg/types/responses" + "testing" + + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/require" +) + +func TestDataFetcherFetchCommissionCachedOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("chain_commission_validator_100", []responses.Commission{ + {Amount: "100", Denom: "ustake"}, + }) + + data, fetched := dataFetcher.GetCommissionAtBlock(config.Chains[0], "validator", 100) + require.True(t, fetched) + require.Len(t, data, 1) + require.Equal(t, "100", data[0].Amount) + require.Equal(t, "ustake", data[0].Denom) +} + +func TestDataFetcherFetchCommissionCachedNotOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("chain_commission_validator_100", nil) + + data, fetched := dataFetcher.GetCommissionAtBlock(config.Chains[0], "validator", 100) + require.False(t, fetched) + require.Empty(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchCommissionAllQueriesFailed(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain", APINodes: []string{"https://example.com"}}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetCommissionAtBlock(config.Chains[0], "validator", 100) + require.False(t, fetched) + require.Empty(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchCommissionSuccessfullyFetched(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder( + "GET", + "https://example.com/cosmos/distribution/v1beta1/validators/validator/commission", + httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("commission.json")), + ) + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain", APINodes: []string{"https://example.com"}}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetCommissionAtBlock(config.Chains[0], "validator", 100) + require.True(t, fetched) + require.Len(t, data, 1) + require.Equal(t, "12345", data[0].Amount) + require.Equal(t, "uatom", data[0].Denom) +} diff --git a/pkg/data_fetcher/fetch_cosmos_directory_chains_test.go b/pkg/data_fetcher/fetch_cosmos_directory_chains_test.go new file mode 100644 index 0000000..3df6125 --- /dev/null +++ b/pkg/data_fetcher/fetch_cosmos_directory_chains_test.go @@ -0,0 +1,118 @@ +package data_fetcher + +import ( + "main/assets" + aliasManagerPkg "main/pkg/alias_manager" + configPkg "main/pkg/config" + "main/pkg/config/types" + "main/pkg/fs" + loggerPkg "main/pkg/logger" + "main/pkg/metrics" + "main/pkg/types/responses" + "testing" + + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/require" +) + +func TestDataFetcherFetchCosmosDirectoryChainsCachedOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("cosmos_directory_chains", responses.CosmosDirectoryChains{ + {ChainID: "chain"}, + }) + + data, fetched := dataFetcher.GetCosmosDirectoryChains() + require.True(t, fetched) + require.Len(t, data, 1) + require.Equal(t, "chain", data[0].ChainID) +} + +func TestDataFetcherFetchCosmosDirectoryChainsCachedNotOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("cosmos_directory_chains", nil) + + data, fetched := dataFetcher.GetCosmosDirectoryChains() + require.False(t, fetched) + require.Empty(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchCosmosDirectoryChainsAllQueriesFailed(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetCosmosDirectoryChains() + require.False(t, fetched) + require.Empty(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchCosmosDirectoryChainsSuccessfullyFetched(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder( + "GET", + "https://chains.cosmos.directory/", + httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("cosmos-directory.json")), + ) + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetCosmosDirectoryChains() + require.True(t, fetched) + require.Len(t, data, 1) + require.Equal(t, "eightball-1", data[0].ChainID) +} diff --git a/pkg/data_fetcher/fetch_denom_trace.go b/pkg/data_fetcher/fetch_denom_trace.go index 7a0b446..fc3fd71 100644 --- a/pkg/data_fetcher/fetch_denom_trace.go +++ b/pkg/data_fetcher/fetch_denom_trace.go @@ -19,7 +19,7 @@ func (f *DataFetcher) GetDenomTrace( denomHash := denomSplit[1] - keyName := chain.Name + "_denom_trace_" + denom + keyName := chain.Name + "_denom_trace_" + denomHash if cachedEntry, cachedEntryPresent := f.Cache.Get(keyName); cachedEntryPresent { if cachedEntryParsed, ok := cachedEntry.(*transferTypes.DenomTrace); ok { diff --git a/pkg/data_fetcher/fetch_denom_trace_test.go b/pkg/data_fetcher/fetch_denom_trace_test.go new file mode 100644 index 0000000..9daab69 --- /dev/null +++ b/pkg/data_fetcher/fetch_denom_trace_test.go @@ -0,0 +1,139 @@ +package data_fetcher + +import ( + "main/assets" + aliasManagerPkg "main/pkg/alias_manager" + configPkg "main/pkg/config" + "main/pkg/config/types" + "main/pkg/fs" + loggerPkg "main/pkg/logger" + "main/pkg/metrics" + "testing" + + transferTypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + "github.com/jarcoal/httpmock" + "github.com/stretchr/testify/require" +) + +func TestDataFetcherFetchDenomTraceInvalidDenom(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetDenomTrace(config.Chains[0], "invalid") + require.False(t, fetched) + require.Nil(t, data) +} + +func TestDataFetcherFetchDenomTraceCachedOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("chain_denom_trace_denom", &transferTypes.DenomTrace{ + Path: "path", + }) + + data, fetched := dataFetcher.GetDenomTrace(config.Chains[0], "ibc/denom") + require.True(t, fetched) + require.NotNil(t, data) + require.Equal(t, "path", data.Path) +} + +func TestDataFetcherFetchDenomTraceCachedNotOk(t *testing.T) { + t.Parallel() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain"}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + dataFetcher.Cache.Set("chain_denom_trace_denom", nil) + + data, fetched := dataFetcher.GetDenomTrace(config.Chains[0], "ibc/denom") + require.False(t, fetched) + require.Nil(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchDenomTraceAllQueriesFailed(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain", APINodes: []string{"https://example.com"}}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetDenomTrace(config.Chains[0], "ibc/denom") + require.False(t, fetched) + require.Nil(t, data) +} + +//nolint:paralleltest // disabled due to httpmock usage +func TestDataFetcherFetchDenomTraceSuccessfullyFetched(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + httpmock.RegisterResponder( + "GET", + "https://example.com/ibc/apps/transfer/v1/denom_traces/denom", + httpmock.NewBytesResponder(200, assets.GetBytesOrPanic("denom-trace.json")), + ) + + config := &configPkg.AppConfig{ + Chains: types.Chains{ + {Name: "chain", APINodes: []string{"https://example.com"}}, + }, + Metrics: configPkg.MetricsConfig{Enabled: false}, + } + + filesystem := &fs.MockFs{} + logger := loggerPkg.GetNopLogger() + aliasManager := aliasManagerPkg.NewAliasManager(logger, config, filesystem) + metricsManager := metrics.NewManager(logger, config.Metrics) + dataFetcher := NewDataFetcher(logger, config, aliasManager, metricsManager) + + data, fetched := dataFetcher.GetDenomTrace(config.Chains[0], "ibc/denom") + require.True(t, fetched) + require.NotNil(t, data) + require.Equal(t, "untrn", data.BaseDenom) +} diff --git a/pkg/filterer/filterer_test.go b/pkg/filterer/filterer_test.go index c94db1c..fb888f0 100644 --- a/pkg/filterer/filterer_test.go +++ b/pkg/filterer/filterer_test.go @@ -18,7 +18,7 @@ import ( func TestFilterMessageUnsupported(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -36,7 +36,7 @@ func TestFilterMessageUnsupported(t *testing.T) { func TestFilterMessageUnparsed(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -54,7 +54,7 @@ func TestFilterMessageUnparsed(t *testing.T) { func TestFilterMessageSimpleNotMatching(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -78,7 +78,7 @@ func TestFilterMessageSimpleNotMatching(t *testing.T) { func TestFilterMessageSimpleMatching(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -102,7 +102,7 @@ func TestFilterMessageSimpleMatching(t *testing.T) { func TestFilterMessageSimpleRecursiveMatchingExternalAndIgnoreInternal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -133,7 +133,7 @@ func TestFilterMessageSimpleRecursiveMatchingExternalAndIgnoreInternal(t *testin func TestFilterMessageSimpleRecursiveMatchingExternalAndFilterInternal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -164,7 +164,7 @@ func TestFilterMessageSimpleRecursiveMatchingExternalAndFilterInternal(t *testin func TestFilterMessageSimpleRecursiveMatchingExternalAndInternal(t *testing.T) { t.Parallel() - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() config := &configPkg.AppConfig{} filterer := filtererPkg.NewFilterer(logger, config, nil) @@ -197,7 +197,7 @@ func TestFilterReportableTxError(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -217,7 +217,7 @@ func TestFilterReportableTxNodeConnectError(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -237,7 +237,7 @@ func TestFilterReportableNotSupported(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -252,7 +252,7 @@ func TestFilterReportableTxFailed(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -290,7 +290,7 @@ func TestFilterReportableTxProcessedBefore(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -325,7 +325,7 @@ func TestFilterReportableTxAllMessagesFiltered(t *testing.T) { t.Parallel() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -361,7 +361,7 @@ func TestFilterReportableTxInvalidHeight(t *testing.T) { }() config := &configPkg.AppConfig{} - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) chain := &configTypes.Chain{Name: "chain"} @@ -409,7 +409,7 @@ func TestGetReporters(t *testing.T) { }, }, } - logger := loggerPkg.GetDefaultLogger() + logger := loggerPkg.GetNopLogger() metricsManager := metrics.NewManager(logger, configPkg.MetricsConfig{Enabled: false}) filterer := filtererPkg.NewFilterer(logger, config, metricsManager) report := types.Report{ diff --git a/pkg/fs/mock_fs.go b/pkg/fs/mock_fs.go new file mode 100644 index 0000000..f15a60b --- /dev/null +++ b/pkg/fs/mock_fs.go @@ -0,0 +1,52 @@ +package fs + +import ( + "errors" + "main/assets" +) + +type MockFile struct { + FailWrite bool + FailClose bool +} + +func (file *MockFile) Write(p []byte) (int, error) { + if file.FailWrite { + return 1, errors.New("not yet supported") + } + + return len(p), nil +} + +func (file *MockFile) Close() error { + if file.FailClose { + return errors.New("not yet supported") + } + + return nil +} + +type MockFs struct { + FailCreate bool + FailWrite bool + FailClose bool +} + +func (filesystem *MockFs) ReadFile(name string) ([]byte, error) { + return assets.EmbedFS.ReadFile(name) +} + +func (filesystem *MockFs) Create(path string) (File, error) { + if filesystem.FailCreate { + return nil, errors.New("not yet supported") + } + + return &MockFile{ + FailWrite: filesystem.FailWrite, + FailClose: filesystem.FailClose, + }, nil +} + +func (filesystem *MockFs) Write(p []byte) (int, error) { + return 0, errors.New("not yet supported") +}