code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/the_vesting_stats_should_be.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package steps
    17  
    18  import (
    19  	"errors"
    20  	"fmt"
    21  	"strings"
    22  
    23  	"code.vegaprotocol.io/vega/core/integration/stubs"
    24  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    25  
    26  	"github.com/cucumber/godog"
    27  	"golang.org/x/exp/maps"
    28  	"golang.org/x/exp/slices"
    29  )
    30  
    31  func TheVestingStatsShouldBe(broker *stubs.BrokerStub, epochStr string, table *godog.Table) error {
    32  	epoch, err := U64(epochStr)
    33  	if err != nil {
    34  		return fmt.Errorf("could not parse epoch: %w", err)
    35  	}
    36  
    37  	expectedVestingStatsStats, err := parseVestingStatsShouldBeTable(table)
    38  	if err != nil {
    39  		return fmt.Errorf("table is invalid: %w", err)
    40  	}
    41  
    42  	vestingStats := broker.VestingStats()
    43  
    44  	foundStreaksForEpoch := map[string]eventspb.PartyVestingStats{}
    45  	for _, stats := range vestingStats {
    46  		if stats.AtEpoch == epoch {
    47  			return compareVestingStats(expectedVestingStatsStats, foundStreaksForEpoch)
    48  		}
    49  	}
    50  
    51  	return fmt.Errorf("no vesting stats found for epoch %q", epochStr)
    52  }
    53  
    54  func parseVestingStatsShouldBeTable(table *godog.Table) (map[string]eventspb.PartyVestingStats, error) {
    55  	rows := StrictParseTable(table, []string{
    56  		"party",
    57  		"reward bonus multiplier",
    58  	}, []string{})
    59  
    60  	stats := map[string]eventspb.PartyVestingStats{}
    61  	for _, row := range rows {
    62  		specificRow := newVestingStatsShouldBeRow(row)
    63  		partyID := specificRow.Party()
    64  		_, alreadyRegistered := stats[partyID]
    65  		if alreadyRegistered {
    66  			return nil, fmt.Errorf("cannot have more than one expectation for party %q", partyID)
    67  		}
    68  		stats[partyID] = eventspb.PartyVestingStats{
    69  			PartyId:               partyID,
    70  			RewardBonusMultiplier: specificRow.RewardBonusMultiplier(),
    71  		}
    72  	}
    73  
    74  	return stats, nil
    75  }
    76  
    77  func compareVestingStats(expectedVestingStats map[string]eventspb.PartyVestingStats, foundVestingStats map[string]eventspb.PartyVestingStats) error {
    78  	foundVestingStatsIDs := maps.Keys(expectedVestingStats)
    79  	expectedVestingStatsIDs := maps.Keys(expectedVestingStats)
    80  
    81  	slices.Sort(foundVestingStatsIDs)
    82  	slices.Sort(expectedVestingStatsIDs)
    83  
    84  	unexpectedParties := []string{}
    85  	partiesNotFound := []string{}
    86  
    87  	for _, expectedID := range expectedVestingStatsIDs {
    88  		if _, ok := foundVestingStats[expectedID]; !ok {
    89  			partiesNotFound = append(partiesNotFound, expectedID)
    90  		}
    91  	}
    92  
    93  	for _, foundID := range foundVestingStatsIDs {
    94  		if _, ok := expectedVestingStats[foundID]; !ok {
    95  			unexpectedParties = append(unexpectedParties, foundID)
    96  		}
    97  	}
    98  
    99  	var errStr string
   100  	if len(partiesNotFound) > 0 {
   101  		errStr = "parties not found: " + strings.Join(partiesNotFound, ", ")
   102  	}
   103  	if len(unexpectedParties) > 0 {
   104  		if errStr != "" {
   105  			errStr += ", and "
   106  		}
   107  		errStr += "unexpected parties: " + strings.Join(unexpectedParties, ", ")
   108  	}
   109  	if errStr != "" {
   110  		return errors.New(errStr)
   111  	}
   112  
   113  	for _, party := range expectedVestingStatsIDs {
   114  		foundActivityStreak := foundVestingStats[party]
   115  		expectedActivityStreak := expectedVestingStats[party]
   116  
   117  		if expectedActivityStreak.RewardBonusMultiplier != foundActivityStreak.RewardBonusMultiplier {
   118  			return formatDiff(
   119  				fmt.Sprintf("vesting stats did not match for party %q", party),
   120  				map[string]string{
   121  					"reward bonus multiplier": expectedActivityStreak.RewardBonusMultiplier,
   122  				},
   123  				map[string]string{
   124  					"reward bonus multiplier": foundActivityStreak.RewardBonusMultiplier,
   125  				},
   126  			)
   127  		}
   128  	}
   129  
   130  	return nil
   131  }
   132  
   133  type vestingStatsShouldBeRow struct {
   134  	row RowWrapper
   135  }
   136  
   137  func newVestingStatsShouldBeRow(r RowWrapper) vestingStatsShouldBeRow {
   138  	return vestingStatsShouldBeRow{
   139  		row: r,
   140  	}
   141  }
   142  
   143  func (r vestingStatsShouldBeRow) Party() string {
   144  	return r.row.MustStr("party")
   145  }
   146  
   147  func (r vestingStatsShouldBeRow) RewardBonusMultiplier() string {
   148  	return r.row.MustStr("reward bonus multiplier")
   149  }