Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stats comparison #1055

Merged
merged 29 commits into from
May 5, 2024
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3de2343
Compare stats eventsDB & MPT
CristalWilsonLobo Apr 9, 2024
b4acf85
mpt storage retrieval details
CristalWilsonLobo Apr 12, 2024
aeac8a2
fetch individual provider details
CristalWilsonLobo Apr 12, 2024
91d9582
Fetch MPT, events DB data
CristalWilsonLobo Apr 16, 2024
63e29b1
Updated blobbers fetch
CristalWilsonLobo Apr 19, 2024
3a2061c
wallet ID added for MPT call
CristalWilsonLobo Apr 20, 2024
6723b92
fetch provider specific node details
CristalWilsonLobo Apr 20, 2024
3707380
Blobber stats comparison
CristalWilsonLobo Apr 21, 2024
88d6b4d
Blobber stats assert
CristalWilsonLobo Apr 21, 2024
f743597
Miner Sharder TC
CristalWilsonLobo Apr 21, 2024
fc28fc1
Blobber MPT to json
CristalWilsonLobo Apr 23, 2024
4219d45
fixed to current sprint branch in tokenomics_ci.yml
shahnawaz-creator Apr 24, 2024
07f434c
Fix current branch for challenge nightly tests workflow
Jayashsatolia403 Apr 24, 2024
b917486
Fix current branch for tokenomics nightly tests workflow
Jayashsatolia403 Apr 24, 2024
1729cb3
Fix current branch for tokenomics nightly tests workflow
Jayashsatolia403 Apr 24, 2024
5107dbc
Type conversion for nested maps
CristalWilsonLobo Apr 25, 2024
d17baf8
Additional fields check added for providers
CristalWilsonLobo Apr 26, 2024
89de72e
Lint issues
CristalWilsonLobo Apr 27, 2024
8b4e38a
Comment formatting
CristalWilsonLobo Apr 27, 2024
f44d1b7
ignore comments - lint
CristalWilsonLobo Apr 27, 2024
4db26b6
Whitespace issue - Lint
CristalWilsonLobo Apr 27, 2024
d5819e6
Remove commented code - Lint
CristalWilsonLobo Apr 27, 2024
ecd94d5
Code restructure - Lint
CristalWilsonLobo Apr 27, 2024
95a6f4c
fmt handle err replaced with test logging
CristalWilsonLobo Apr 30, 2024
499fb51
Merge branch 'master' into stats_comparison
Jayashsatolia403 Apr 30, 2024
d0e1666
Merge branch 'refs/heads/sprint-1.14' into stats_comparison
Jayashsatolia403 Apr 30, 2024
d6d14ff
Run in the very end
Jayashsatolia403 May 3, 2024
bdd8d83
Empty commit
Jayashsatolia403 May 3, 2024
af3fc78
Revert workflow changes
Jayashsatolia403 May 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
334 changes: 334 additions & 0 deletions tests/cli_tests/zzzzwalletcli_compare_stats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,334 @@
package cli_tests

import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"strings"
"testing"

"github.com/0chain/system_test/internal/api/util/test"

"github.com/0chain/system_test/internal/api/util/client"
"github.com/0chain/system_test/internal/api/util/config"
"github.com/stretchr/testify/require"
)

var (
apiClient *client.APIClient
)

type customDataMap map[string]interface{}

func TestMonitoringCompareMPTAndEventsDBData(testSetup *testing.T) {
t := setUpTest(testSetup)
createWallet(t)
t.Log("Default Config File ", configPath)
parsedConfig := config.Parse("./config/" + configPath)
apiClient = client.NewAPIClient(parsedConfig.BlockWorker)

compareBlobbersData(t)
compareShardersData(t)
compareMinersData(t)
}

func setUpTest(t *testing.T) *test.SystemTest {
tSetup := test.NewSystemTest(t)
return tSetup
}

func compareBlobbersData(t *test.SystemTest) {
// Fetch base URLs for all blobbers
blobberBaseURLs := make(map[string]string)

for _, blobberURL := range apiClient.HealthyServiceProviders.Blobbers {
parsedURL, err := url.Parse(blobberURL)
if err != nil {
t.Log("Error parsing URL:", err)
continue
}

// Extract the last segment from the URL path as the blobber ID
segments := strings.Split(parsedURL.Path, "/")
blobberID := segments[len(segments)-1]
blobberBaseURLs[blobberID] = blobberURL

t.Log("Fetched blobber URL:", blobberURL)
}

// I - Test Case for Blobber
t.RunSequentially("Compare data in MPT with events DB for blobbers", func(t *test.SystemTest) {
// Fetch all blobbers from Events DB via "/v1/screst/:sc_address/getblobbers" endpoint
blobbers, resp, err := apiClient.V1SCRestGetAllBlobbers(t, client.HttpOkStatus)

require.NoError(t, err, "Failed to fetch blobbers")
require.Equal(t, 200, resp.StatusCode(), "Expected HTTP status code 200")
require.NotEmpty(t, blobbers, "Blobbers list should not be empty")

for _, blobber := range blobbers {
t.Logf("Blobber ID: %s, URL: %s", blobber.ID, blobber.BaseURL)
t.Logf("*** Blobber Response Body from Events DB ***")
t.Log(blobber)
t.Logf("***")
// Fetch Blobbers from MPT data structure
fullURL := fmt.Sprintf("%s%s?key=provider:%s", apiClient.HealthyServiceProviders.Sharders[0], client.SCStateGet, blobber.ID)
t.Logf(fullURL)
response, err := apiClient.HttpClient.R().Get(fullURL)
require.NoError(t, err, "Failed to fetch data from blobber")
require.NotNil(t, response, "Response from blobber should not be nil")

var dataMap customDataMap
// Unmarshal using the custom unmarshal logic.
if err := json.Unmarshal([]byte(response.Body()), &dataMap); err != nil {
t.Logf("Error unmarshalling JSON: %s", err)
}

t.Logf("*** Blobber Response Body from MPT datastructure ***")
t.Log(dataMap)
t.Logf("***")

providerMap, ok := dataMap["Provider"].(map[string]interface{})
if ok {
t.Log("Retrieved provider node from MPT")
}
termsMap, ok := dataMap["Terms"].(map[string]interface{})
if ok {
t.Log("Retrieved terms node from MPT")
}
stakePoolSettingsMap, ok := dataMap["StakePoolSettings"].(map[string]interface{})
if ok {
t.Log("Retrieved stakePoolSettings node from MPT")
}

lastHealthCheckNumber, err := providerMap["LastHealthCheck"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert LastHealthCheck to int64: %v", err)
}

readPriceNumber, err := termsMap["ReadPrice"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert ReadPrice to int64: %v", err)
}

writePriceNumber, err := termsMap["WritePrice"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert WritePrice to int64: %v", err)
}

maxNumDelegatesNumber, err := stakePoolSettingsMap["MaxNumDelegates"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert WritePrice to int64: %v", err)
}

serviceChargeRatioNumber, err := stakePoolSettingsMap["ServiceChargeRatio"].(json.Number).Float64()
if err != nil {
t.Errorf("Failed to convert WritePrice to int64: %v", err)
}
require.Equal(t, blobber.ID, providerMap["ID"], "Blobber ID does not match")
require.Equal(t, blobber.BaseURL, dataMap.GetString("BaseURL"), "Blobber BaseURL does not match")
require.Equal(t, blobber.Capacity, dataMap.GetInt64("Capacity"), "Blobber Capacity does not match")
require.Equal(t, blobber.Allocated, dataMap.GetInt64("Allocated"), "Blobber Allocated does not match")
require.Equal(t, blobber.LastHealthCheck, lastHealthCheckNumber, "Blobber LastHealthCheck does not match")
// require.Equal(t, blobber.PublicKey, dataMap.GetString("PublicKey"), "Blobber PublicKey does not match") # Not in blobber DTO struct //nolint: unused
require.Equal(t, blobber.Terms.ReadPrice, readPriceNumber, "Blobber ReadPrice does not match")
require.Equal(t, blobber.Terms.WritePrice, writePriceNumber, "Blobber WritePrice does not match")
require.Equal(t, blobber.StakePoolSettings.DelegateWallet, stakePoolSettingsMap["DelegateWallet"], "Blobber DelegateWallet does not match")
require.Equal(t, int64(blobber.StakePoolSettings.NumDelegates), maxNumDelegatesNumber, "Blobber MaxNumDelegates does not match")
require.Equal(t, blobber.StakePoolSettings.ServiceCharge, serviceChargeRatioNumber, "Blobber ServiceChargeRatio does not match")
}
})
}

func compareShardersData(t *test.SystemTest) {
// Fetch base URLs for all sharders
sharderBaseURLs := make(map[string]string)

for _, sharderURL := range apiClient.HealthyServiceProviders.Sharders {
parsedURL, err := url.Parse(sharderURL)
if err != nil {
t.Log("Error parsing URL:", err)
continue
}

// Extract the last segment from the URL path as the blobber name
segments := strings.Split(parsedURL.Path, "/")
sharderID := segments[len(segments)-1]
sharderBaseURLs[sharderID] = sharderURL

t.Log("Fetched blobber URL:", sharderURL)
}
// II - Test Case for Sharders
t.RunSequentially("Compare data in MPT with events DB for Sharders", func(t *test.SystemTest) {
sharders, resp, err := apiClient.V1SCRestGetAllSharders(t, client.HttpOkStatus)
require.NoError(t, err, "Failed to fetch sharders")
require.Equal(t, 200, resp.StatusCode(), "Expected HTTP status code 200")
require.NotEmpty(t, sharders, "Sharders list should not be empty")

for _, sharder := range sharders {
sharderURL := fmt.Sprintf("%s%s?key=provider:%s", apiClient.HealthyServiceProviders.Sharders[0], client.SCStateGet, sharder.ID)
response, err := apiClient.HttpClient.R().Get(sharderURL)
require.NoError(t, err, "Failed to fetch data for sharder from MPT "+sharder.ID)
t.Log(sharder)

var dataMap customDataMap
// Unmarshal using the custom unmarshal logic.
if err := json.Unmarshal([]byte(response.Body()), &dataMap); err != nil {
t.Logf("Error unmarshalling JSON: %s", err)
}
t.Log(dataMap)
simpleNodeMap, ok := dataMap["SimpleNode"].(map[string]interface{})
if ok {
t.Log("Retrieved simple node from MPT")
}

totalStakedNumber, err := simpleNodeMap["TotalStaked"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

lastHealthCheckNumber, err := simpleNodeMap["LastHealthCheck"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

lastSettingUpdateRoundNumber, err := simpleNodeMap["LastSettingUpdateRound"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

require.Equal(t, sharder.Host, simpleNodeMap["Host"], "sharder Host does not match")
require.Equal(t, sharder.BuildTag, simpleNodeMap["BuildTag"], "sharder BuildTag does not match")
require.Equal(t, sharder.TotalStaked, totalStakedNumber, "sharder TotalStake does not match")
require.Equal(t, sharder.LastHealthCheck, lastHealthCheckNumber, "sharder LastHealthCheck does not match")
require.Equal(t, sharder.LastSettingUpdateRound, lastSettingUpdateRoundNumber, "sharder LastSettingUpdateRound does not match")
}
})
}

func compareMinersData(t *test.SystemTest) {
// Fetch base URLs for all miners
minerBaseURLs := make(map[string]string)
for _, minerURL := range apiClient.HealthyServiceProviders.Miners {
parsedURL, err := url.Parse(minerURL)
if err != nil {
t.Log("Error parsing URL:", err)
continue
}

// Extract the last segment from the URL path as the blobber name
segments := strings.Split(parsedURL.Path, "/")
minerID := segments[len(segments)-1]
minerBaseURLs[minerID] = minerURL

t.Log("Fetched miner URL:", minerURL)
}

// III Test Case for Miners
t.RunSequentially("Compare data in MPT with events DB for Miners", func(t *test.SystemTest) {
miners, resp, err := apiClient.V1SCRestGetAllMiners(t, client.HttpOkStatus)
require.NoError(t, err, "Failed to fetch miners")
require.Equal(t, 200, resp.StatusCode(), "Expected HTTP status code 200")
require.NotEmpty(t, miners, "Miners list should not be empty")

for _, miner := range miners {
minerURL := fmt.Sprintf("%s%s?key=provider:%s", apiClient.HealthyServiceProviders.Sharders[0], client.SCStateGet, miner.ID)
response, err := apiClient.HttpClient.R().Get(minerURL)
require.NoError(t, err, "Failed to fetch data for miner "+miner.ID)

var dataMap customDataMap
// Unmarshal using the custom unmarshal logic.
if err := json.Unmarshal([]byte(response.Body()), &dataMap); err != nil {
t.Logf("Error unmarshalling JSON: %s", err)
}
t.Log(dataMap)
simpleNodeMap, ok := dataMap["SimpleNode"].(map[string]interface{})
if ok {
t.Log("Retrieved simple node from MPT")
}

totalStakedNumber, err := simpleNodeMap["TotalStaked"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

lastHealthCheckNumber, err := simpleNodeMap["LastHealthCheck"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

lastSettingUpdateRoundNumber, err := simpleNodeMap["LastSettingUpdateRound"].(json.Number).Int64()
if err != nil {
t.Errorf("Failed to convert totalStakedNumber to int64: %v", err)
}

require.Equal(t, miner.Host, simpleNodeMap["Host"], "miner Host does not match")
require.Equal(t, miner.BuildTag, simpleNodeMap["BuildTag"], "miner BuildTag does not match")
require.Equal(t, miner.TotalStaked, totalStakedNumber, "miner TotalStake does not match")
require.Equal(t, miner.LastHealthCheck, lastHealthCheckNumber, "miner LastHealthCheck does not match")
require.Equal(t, miner.LastSettingUpdateRound, lastSettingUpdateRoundNumber, "miner LastSettingUpdateRound does not match")
}
})
}

func (cdm *customDataMap) UnmarshalJSON(data []byte) error {
temp := map[string]interface{}{}

dec := json.NewDecoder(bytes.NewReader(data))
dec.UseNumber()

if err := dec.Decode(&temp); err != nil {
return err
}

// Convert json.Number into int64 or float64
for key, value := range temp {
if v, ok := value.(json.Number); ok {
if i, err := v.Int64(); err == nil {
temp[key] = i
} else if f, err := v.Float64(); err == nil {
temp[key] = f
}
}
}

*cdm = temp
return nil
}

func (cdm customDataMap) GetString(key string) string {
if val, ok := cdm[key]; ok {
if str, ok := val.(string); ok {
return str
}
}
return ""
}

func (cdm customDataMap) GetInt64(key string) int64 {
if val, ok := cdm[key]; ok {
switch v := val.(type) {
case int64:
return v
case json.Number:
if i, err := v.Int64(); err == nil {
return i
}
}
}
return 0
}

func (cdm customDataMap) GetFloat64(key string) float64 {
if val, ok := cdm[key]; ok {
switch v := val.(type) {
case float64:
return v
case json.Number:
if f, err := v.Float64(); err == nil {
return f
}
}
}
return 0.0
}