code.vegaprotocol.io/vega@v0.79.0/core/integration/steps/the_activity_streaks_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 "strconv" 22 "strings" 23 24 "code.vegaprotocol.io/vega/core/integration/stubs" 25 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 26 27 "github.com/cucumber/godog" 28 "golang.org/x/exp/maps" 29 "golang.org/x/exp/slices" 30 ) 31 32 func TheActivityStreaksShouldBe(broker *stubs.BrokerStub, epochStr string, table *godog.Table) error { 33 epoch, err := U64(epochStr) 34 if err != nil { 35 return fmt.Errorf("could not parse epoch: %w", err) 36 } 37 38 expectedActivityStreaksStats, err := parseActivityStreaksShouldBeTable(table) 39 if err != nil { 40 return fmt.Errorf("table is invalid: %w", err) 41 } 42 43 allStreaks := broker.PartyActivityStreaks() 44 45 foundStreaksForEpoch := map[string]eventspb.PartyActivityStreak{} 46 for _, streak := range allStreaks { 47 if streak.Epoch == epoch { 48 foundStreaksForEpoch[streak.Party] = streak 49 } 50 } 51 52 if len(foundStreaksForEpoch) == 0 && len(expectedActivityStreaksStats) > 0 { 53 return fmt.Errorf("no activity streaks found at epoch %v", epochStr) 54 } 55 56 return compareActivityStreaks(expectedActivityStreaksStats, foundStreaksForEpoch) 57 } 58 59 func parseActivityStreaksShouldBeTable(table *godog.Table) (map[string]eventspb.PartyActivityStreak, error) { 60 rows := StrictParseTable(table, []string{ 61 "party", 62 "active for", 63 "inactive for", 64 "reward multiplier", 65 "vesting multiplier", 66 }, []string{}) 67 68 stats := map[string]eventspb.PartyActivityStreak{} 69 for _, row := range rows { 70 specificRow := newActivityStreaksShouldBeRow(row) 71 partyID := specificRow.Party() 72 _, alreadyRegistered := stats[partyID] 73 if alreadyRegistered { 74 return nil, fmt.Errorf("cannot have more than one expectation for party %q", partyID) 75 } 76 stats[partyID] = eventspb.PartyActivityStreak{ 77 Party: partyID, 78 ActiveFor: specificRow.ActiveFor(), 79 InactiveFor: specificRow.InactiveFor(), 80 RewardDistributionActivityMultiplier: specificRow.RewardMultiplier(), 81 RewardVestingActivityMultiplier: specificRow.VestingMultiplier(), 82 } 83 } 84 85 return stats, nil 86 } 87 88 func compareActivityStreaks(expectedActivityStreaks map[string]eventspb.PartyActivityStreak, foundActivityStreaks map[string]eventspb.PartyActivityStreak) error { 89 foundActivityStreaksIDs := maps.Keys(expectedActivityStreaks) 90 expectedActivityStreaksIDs := maps.Keys(expectedActivityStreaks) 91 92 slices.Sort(foundActivityStreaksIDs) 93 slices.Sort(expectedActivityStreaksIDs) 94 95 unexpectedParties := []string{} 96 partiesNotFound := []string{} 97 98 for _, expectedID := range expectedActivityStreaksIDs { 99 if _, ok := foundActivityStreaks[expectedID]; !ok { 100 partiesNotFound = append(partiesNotFound, expectedID) 101 } 102 } 103 104 for _, foundID := range foundActivityStreaksIDs { 105 if _, ok := expectedActivityStreaks[foundID]; !ok { 106 unexpectedParties = append(unexpectedParties, foundID) 107 } 108 } 109 110 var errStr string 111 if len(partiesNotFound) > 0 { 112 errStr = "parties not found: " + strings.Join(partiesNotFound, ", ") 113 } 114 if len(unexpectedParties) > 0 { 115 if errStr != "" { 116 errStr += ", and " 117 } 118 errStr += "unexpected parties: " + strings.Join(unexpectedParties, ", ") 119 } 120 if errStr != "" { 121 return errors.New(errStr) 122 } 123 124 for _, party := range expectedActivityStreaksIDs { 125 foundActivityStreak := foundActivityStreaks[party] 126 expectedActivityStreak := expectedActivityStreaks[party] 127 128 if expectedActivityStreak.ActiveFor != foundActivityStreak.ActiveFor || 129 expectedActivityStreak.InactiveFor != foundActivityStreak.InactiveFor || 130 expectedActivityStreak.RewardDistributionActivityMultiplier != foundActivityStreak.RewardDistributionActivityMultiplier || 131 expectedActivityStreak.RewardVestingActivityMultiplier != foundActivityStreak.RewardVestingActivityMultiplier { 132 return formatDiff( 133 fmt.Sprintf("activity streak did not match for party %q", party), 134 map[string]string{ 135 "active for": strconv.FormatUint(expectedActivityStreak.ActiveFor, 10), 136 "inactive for": strconv.FormatUint(expectedActivityStreak.InactiveFor, 10), 137 "reward multiplier": expectedActivityStreak.RewardDistributionActivityMultiplier, 138 "vesting multiplier": expectedActivityStreak.RewardVestingActivityMultiplier, 139 }, 140 map[string]string{ 141 "active for": strconv.FormatUint(foundActivityStreak.ActiveFor, 10), 142 "inactive for": strconv.FormatUint(foundActivityStreak.InactiveFor, 10), 143 "reward multiplier": foundActivityStreak.RewardDistributionActivityMultiplier, 144 "vesting multiplier": foundActivityStreak.RewardVestingActivityMultiplier, 145 }, 146 ) 147 } 148 } 149 150 return nil 151 } 152 153 type activityStreaksShouldBeRow struct { 154 row RowWrapper 155 } 156 157 func newActivityStreaksShouldBeRow(r RowWrapper) activityStreaksShouldBeRow { 158 row := activityStreaksShouldBeRow{ 159 row: r, 160 } 161 return row 162 } 163 164 func (r activityStreaksShouldBeRow) Party() string { 165 return r.row.MustStr("party") 166 } 167 168 func (r activityStreaksShouldBeRow) ActiveFor() uint64 { 169 return r.row.MustU64("active for") 170 } 171 172 func (r activityStreaksShouldBeRow) InactiveFor() uint64 { 173 return r.row.MustU64("inactive for") 174 } 175 176 func (r activityStreaksShouldBeRow) RewardMultiplier() string { 177 return r.row.MustStr("reward multiplier") 178 } 179 180 func (r activityStreaksShouldBeRow) VestingMultiplier() string { 181 return r.row.MustStr("vesting multiplier") 182 }