code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/the_volume_discount_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 TheVolumeDiscountStatsShouldBe(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  	expectedVolumeDiscountStatsStats, err := parseVolumeDiscountStatsShouldBeTable(table)
    38  	if err != nil {
    39  		return fmt.Errorf("table is invalid: %w", err)
    40  	}
    41  
    42  	VolumeDiscountStats := broker.VolumeDiscountStats()
    43  
    44  	foundStreaksForEpoch := map[string]eventspb.PartyVolumeDiscountStats{}
    45  	for _, stats := range VolumeDiscountStats {
    46  		if stats.AtEpoch == epoch {
    47  			return compareVolumeDiscountStats(expectedVolumeDiscountStatsStats, foundStreaksForEpoch)
    48  		}
    49  	}
    50  
    51  	return fmt.Errorf("no volume discount stats found for epoch %q", epochStr)
    52  }
    53  
    54  func parseVolumeDiscountStatsShouldBeTable(table *godog.Table) (map[string]eventspb.PartyVolumeDiscountStats, error) {
    55  	rows := StrictParseTable(table, []string{
    56  		"party",
    57  		"running volume",
    58  		"discount factor",
    59  	}, []string{})
    60  
    61  	stats := map[string]eventspb.PartyVolumeDiscountStats{}
    62  	for _, row := range rows {
    63  		specificRow := newVolumeDiscountStatsShouldBeRow(row)
    64  		partyID := specificRow.Party()
    65  		_, alreadyRegistered := stats[partyID]
    66  		if alreadyRegistered {
    67  			return nil, fmt.Errorf("cannot have more than one expectation for party %q", partyID)
    68  		}
    69  		stats[partyID] = eventspb.PartyVolumeDiscountStats{
    70  			PartyId:        partyID,
    71  			DiscountFactor: specificRow.DiscountFactor(),
    72  			RunningVolume:  specificRow.RunningVolume(),
    73  		}
    74  	}
    75  
    76  	return stats, nil
    77  }
    78  
    79  func compareVolumeDiscountStats(expectedStats, foundStats map[string]eventspb.PartyVolumeDiscountStats) error {
    80  	foundStatsIDs := maps.Keys(expectedStats)
    81  	expectedStatsIDs := maps.Keys(expectedStats)
    82  
    83  	slices.Sort(foundStatsIDs)
    84  	slices.Sort(expectedStatsIDs)
    85  
    86  	unexpectedParties := []string{}
    87  	partiesNotFound := []string{}
    88  
    89  	for _, expectedID := range expectedStatsIDs {
    90  		if _, ok := foundStats[expectedID]; !ok {
    91  			partiesNotFound = append(partiesNotFound, expectedID)
    92  		}
    93  	}
    94  
    95  	for _, foundID := range foundStatsIDs {
    96  		if _, ok := expectedStats[foundID]; !ok {
    97  			unexpectedParties = append(unexpectedParties, foundID)
    98  		}
    99  	}
   100  
   101  	var errStr string
   102  	if len(partiesNotFound) > 0 {
   103  		errStr = "parties not found: " + strings.Join(partiesNotFound, ", ")
   104  	}
   105  	if len(unexpectedParties) > 0 {
   106  		if errStr != "" {
   107  			errStr += ", and "
   108  		}
   109  		errStr += "unexpected parties: " + strings.Join(unexpectedParties, ", ")
   110  	}
   111  	if errStr != "" {
   112  		return errors.New(errStr)
   113  	}
   114  
   115  	for _, party := range expectedStatsIDs {
   116  		foundActivityStreak := foundStats[party]
   117  		expectedActivityStreak := expectedStats[party]
   118  
   119  		if expectedActivityStreak.RunningVolume != foundActivityStreak.RunningVolume ||
   120  			expectedActivityStreak.DiscountFactor != foundActivityStreak.DiscountFactor {
   121  			return formatDiff(
   122  				fmt.Sprintf("Volume discount stats did not match for party %q", party),
   123  				map[string]string{
   124  					"running volume":  expectedActivityStreak.RunningVolume,
   125  					"discount factor": expectedActivityStreak.DiscountFactor,
   126  				},
   127  				map[string]string{
   128  					"running volume":  foundActivityStreak.RunningVolume,
   129  					"discount factor": foundActivityStreak.DiscountFactor,
   130  				},
   131  			)
   132  		}
   133  	}
   134  
   135  	return nil
   136  }
   137  
   138  type volumeDiscountStatsShouldBeRow struct {
   139  	row RowWrapper
   140  }
   141  
   142  func newVolumeDiscountStatsShouldBeRow(r RowWrapper) volumeDiscountStatsShouldBeRow {
   143  	return volumeDiscountStatsShouldBeRow{
   144  		row: r,
   145  	}
   146  }
   147  
   148  func (r volumeDiscountStatsShouldBeRow) Party() string {
   149  	return r.row.MustStr("party")
   150  }
   151  
   152  func (r volumeDiscountStatsShouldBeRow) DiscountFactor() string {
   153  	return r.row.MustStr("discount factor")
   154  }
   155  
   156  func (r volumeDiscountStatsShouldBeRow) RunningVolume() string {
   157  	return r.row.MustStr("running volume")
   158  }