github.com/DapperCollectives/CAST/backend@v0.0.0-20230921221157-1350c8be7c96/tests/leaderboard_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "net/http" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/DapperCollectives/CAST/backend/main/models" 11 "github.com/DapperCollectives/CAST/backend/tests/test_utils" 12 "github.com/stretchr/testify/assert" 13 ) 14 15 func resetTables() { 16 clearTable("communities") 17 clearTable("balances") 18 clearTable("community_users") 19 clearTable("proposals") 20 clearTable("votes") 21 } 22 23 func TestGetLeaderboardCurrentUser(t *testing.T) { 24 resetTables() 25 26 communityId := otu.AddCommunities(1, "dao")[0] 27 proposalId := otu.AddActiveProposals(communityId, 1)[0] 28 vote := otu.GenerateValidVotePayload("user1", proposalId, "a") 29 otu.CreateVoteAPI(proposalId, vote) 30 31 response := otu.GetCommunityLeaderboardAPI(communityId) 32 checkResponseCode(t, http.StatusOK, response.Code) 33 34 var p1 test_utils.PaginatedResponseWithLeaderboardUser 35 json.Unmarshal(response.Body.Bytes(), &p1) 36 37 assert.Equal(t, models.LeaderboardUser{}, p1.Data.CurrentUser) 38 39 response = otu.GetCommunityLeaderboardAPIWithCurrentUser(communityId, vote.Addr) 40 checkResponseCode(t, http.StatusOK, response.Code) 41 42 var p2 test_utils.PaginatedResponseWithLeaderboardUser 43 json.Unmarshal(response.Body.Bytes(), &p2) 44 45 assert.Equal(t, vote.Addr, p2.Data.CurrentUser.Addr) 46 } 47 48 func TestGetLeaderboardWithEarlyVotes(t *testing.T) { 49 resetTables() 50 51 communityId := otu.AddCommunities(1, "dao")[0] 52 earlyVoteBonus := 1 53 expectedUsers := 1 54 expectedProposals := 2 55 56 // user gets single vote for each proposal they voted on 57 expectedScore := expectedProposals + (expectedProposals * earlyVoteBonus) 58 59 otu.GenerateEarlyVoteAchievements(communityId, expectedProposals, expectedUsers) 60 61 response := otu.GetCommunityLeaderboardAPI(communityId) 62 checkResponseCode(t, http.StatusOK, response.Code) 63 64 var p test_utils.PaginatedResponseWithLeaderboardUser 65 json.Unmarshal(response.Body.Bytes(), &p) 66 67 users := p.Data.Users 68 69 receivedScore := users[0].Score 70 71 assert.Equal(t, expectedUsers, len(users)) 72 assert.Equal(t, expectedScore, receivedScore) 73 } 74 75 func TestGetLeaderboardWithSingleStreak(t *testing.T) { 76 resetTables() 77 78 communityId := otu.AddCommunities(1, "dao")[0] 79 streaks := []int{3, 4} 80 streakBonus := 1 81 expectedUsers := len(streaks) 82 expectedScoreA := streaks[0] + (1 * streakBonus) 83 expectedScoreB := streaks[1] + (1 * streakBonus) 84 85 otu.GenerateSingleStreakAchievements(communityId, streaks) 86 87 response := otu.GetCommunityLeaderboardAPI(communityId) 88 checkResponseCode(t, http.StatusOK, response.Code) 89 90 var p test_utils.PaginatedResponseWithLeaderboardUser 91 json.Unmarshal(response.Body.Bytes(), &p) 92 93 users := p.Data.Users 94 95 // ensure scores ordered for assert 96 sort.Slice(users, func(i, j int) bool { 97 return users[i].Score < users[j].Score 98 }) 99 100 receivedScoreA := users[0].Score 101 receivedScoreB := users[1].Score 102 103 assert.Equal(t, expectedUsers, len(users)) 104 assert.Equal(t, expectedScoreA, receivedScoreA) 105 assert.Equal(t, expectedScoreB, receivedScoreB) 106 } 107 108 func TestGetLeaderboardWithMultiStreaks(t *testing.T) { 109 resetTables() 110 111 communityId := otu.AddCommunities(1, "dao")[0] 112 streaks := []int{3, 4} 113 streakBonus := 1 114 expectedUsers := 1 115 116 // user with 7 votes and 2 streaks 117 expectedUser1Score := 7 + (2 * streakBonus) 118 119 otu.GenerateMultiStreakAchievements(communityId, streaks) 120 121 response := otu.GetCommunityLeaderboardAPI(communityId) 122 checkResponseCode(t, http.StatusOK, response.Code) 123 124 var p test_utils.PaginatedResponseWithLeaderboardUser 125 json.Unmarshal(response.Body.Bytes(), &p) 126 127 users := p.Data.Users 128 129 receivedUser1Score := users[0].Score 130 131 assert.Equal(t, expectedUsers, len(users)) 132 assert.Equal(t, expectedUser1Score, receivedUser1Score) 133 } 134 135 func TestGetLeaderboardWithWinningVote(t *testing.T) { 136 resetTables() 137 138 communityId := otu.AddCommunities(1, "dao")[0] 139 winningVoteBonus := 1 140 141 proposalId := otu.GenerateWinningVoteAchievement(communityId, "token-weighted-default") 142 otu.UpdateProposalEndTime(proposalId, time.Now().UTC()) 143 otu.GetProposalResultsAPI(proposalId) 144 145 response := otu.GetCommunityLeaderboardAPI(communityId) 146 checkResponseCode(t, http.StatusOK, response.Code) 147 148 var p test_utils.PaginatedResponseWithLeaderboardUser 149 json.Unmarshal(response.Body.Bytes(), &p) 150 151 users := p.Data.Users 152 153 winningUserScore := 1 + 1*winningVoteBonus 154 losingUserScore := 1 155 156 receivedWinners := 0 157 receivedLosers := 0 158 159 for _, user := range users { 160 if user.Score == winningUserScore { 161 receivedWinners += 1 162 } else if user.Score == losingUserScore { 163 receivedLosers += 1 164 } 165 } 166 167 expectedWinners := 3 168 expectedLosers := 1 169 170 assert.Equal(t, expectedWinners, receivedWinners) 171 assert.Equal(t, expectedLosers, receivedLosers) 172 } 173 174 func TestGetLeaderboardWithCancelledProposal(t *testing.T) { 175 authorName := "user1" 176 177 t.Run("User should lose vote on cancelled proposal", func(t *testing.T) { 178 resetTables() 179 communityId := otu.AddCommunitiesWithUsers(1, authorName)[0] 180 proposalIds := otu.AddActiveProposals(communityId, 3) 181 182 for _, id := range proposalIds { 183 vote := otu.GenerateValidVotePayload(authorName, id, "a") 184 otu.CreateVoteAPI(id, vote) 185 } 186 187 // Cancel proposal 188 cancelPayload := otu.GenerateCancelProposalStruct(authorName, proposalIds[1]) 189 otu.UpdateProposalAPI(proposalIds[1], cancelPayload) 190 191 response := otu.GetCommunityLeaderboardAPI(communityId) 192 checkResponseCode(t, http.StatusOK, response.Code) 193 194 var p test_utils.PaginatedResponseWithLeaderboardUser 195 json.Unmarshal(response.Body.Bytes(), &p) 196 197 assert.Equal(t, 2, p.Data.Users[0].Score) 198 }) 199 200 t.Run("User should lose early vote achievement on cancelled proposal", func(t *testing.T) { 201 numProposals := 4 202 communityId := otu.AddCommunitiesWithUsers(1, authorName)[0] 203 proposalIds := otu.GenerateEarlyVoteAchievements(communityId, numProposals, 1) 204 205 // Cancel a proposalId 206 cancelPayload := otu.GenerateCancelProposalStruct(authorName, proposalIds[1]) 207 otu.UpdateProposalAPI(proposalIds[1], cancelPayload) 208 209 response := otu.GetCommunityLeaderboardAPI(communityId) 210 checkResponseCode(t, http.StatusOK, response.Code) 211 212 var p test_utils.PaginatedResponseWithLeaderboardUser 213 json.Unmarshal(response.Body.Bytes(), &p) 214 215 // User get votes + early votes, but no extra on cancelled proposal 216 expectedResult := (numProposals - 1) * 2 217 assert.Equal(t, expectedResult, p.Data.Users[0].Score) 218 }) 219 } 220 221 func TestGetLeaderboardDefaultPaging(t *testing.T) { 222 resetTables() 223 224 communityId := otu.AddCommunities(1, "dao")[0] 225 226 numUsers := 6 227 numProposals := 1 228 229 otu.GenerateVotes(communityId, numProposals, numUsers) 230 231 response := otu.GetCommunityLeaderboardAPI(communityId) 232 checkResponseCode(t, http.StatusOK, response.Code) 233 234 var p test_utils.PaginatedResponseWithLeaderboardUser 235 json.Unmarshal(response.Body.Bytes(), &p) 236 237 expectedLength := 6 238 assert.Equal(t, expectedLength, len(p.Data.Users)) 239 } 240 241 func TestGetLeaderboardPaging(t *testing.T) { 242 resetTables() 243 244 communityId := otu.AddCommunities(1, "dao")[0] 245 246 otu.AddActiveProposals(communityId, 1) 247 248 count := 3 249 250 // Leaderboard with no users because no votes yet 251 response1 := otu.GetCommunityLeaderboardAPIWithPaging(communityId, 0, count) 252 checkResponseCode(t, http.StatusOK, response1.Code) 253 254 var p1 test_utils.PaginatedResponseWithLeaderboardUser 255 json.Unmarshal(response1.Body.Bytes(), &p1) 256 257 numUsers := 6 258 numProposals := 1 259 260 otu.GenerateVotes(communityId, numProposals, numUsers) 261 262 // First Page 263 response2 := otu.GetCommunityLeaderboardAPIWithPaging(communityId, 0, count) 264 checkResponseCode(t, http.StatusOK, response2.Code) 265 266 var p2 test_utils.PaginatedResponseWithLeaderboardUser 267 json.Unmarshal(response2.Body.Bytes(), &p2) 268 269 // Second Page 270 response3 := otu.GetCommunityLeaderboardAPIWithPaging(communityId, 1, count) 271 checkResponseCode(t, http.StatusOK, response3.Code) 272 273 var p3 test_utils.PaginatedResponseWithLeaderboardUser 274 json.Unmarshal(response3.Body.Bytes(), &p3) 275 276 // Invalid Page 277 response4 := otu.GetCommunityLeaderboardAPIWithPaging(communityId, 3, count) 278 checkResponseCode(t, http.StatusOK, response4.Code) 279 280 var p4 test_utils.PaginatedResponseWithLeaderboardUser 281 json.Unmarshal(response4.Body.Bytes(), &p4) 282 283 expectedNoUsersLength := 0 284 expectedLength := 3 285 assert.Equal(t, expectedNoUsersLength, len(p1.Data.Users)) 286 assert.Equal(t, expectedLength, len(p2.Data.Users)) 287 assert.Equal(t, expectedLength, len(p3.Data.Users)) 288 assert.Equal(t, expectedLength, len(p4.Data.Users)) 289 }