code.vegaprotocol.io/vega@v0.79.0/core/teams/engine_test.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 teams_test 17 18 import ( 19 "testing" 20 "time" 21 22 "code.vegaprotocol.io/vega/core/teams" 23 "code.vegaprotocol.io/vega/core/types" 24 vgrand "code.vegaprotocol.io/vega/libs/rand" 25 vgtest "code.vegaprotocol.io/vega/libs/test" 26 vegapb "code.vegaprotocol.io/vega/protos/vega" 27 commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1" 28 29 "github.com/stretchr/testify/assert" 30 "github.com/stretchr/testify/require" 31 ) 32 33 func TestEngine(t *testing.T) { 34 t.Run("Administrate a team succeeds", testAdministrateTeamSucceeds) 35 t.Run("Joining team succeeds", testJoiningTeamSucceeds) 36 t.Run("unique team names", testUniqueTeamNames) 37 t.Run("must be in a team for the minimum number of epochs", testMinEpochsRequired) 38 } 39 40 func testUniqueTeamNames(t *testing.T) { 41 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomI64()) 42 43 te := newEngine(t) 44 45 require.False(t, te.engine.TeamExists(newTeamID(t))) 46 47 referrer1 := newPartyID(t) 48 referrer2 := newPartyID(t) 49 teamID1 := newTeamID(t) 50 teamID2 := newTeamID(t) 51 name := vgrand.RandomStr(5) 52 teamURL := "https://" + name + ".io" 53 avatarURL := "https://avatar." + name + ".io" 54 55 expectTeamCreatedEvent(t, te) 56 57 team1CreationDate := time.Now() 58 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1) 59 60 require.NoError(t, te.engine.CreateTeam(ctx, referrer1, teamID1, createTeamCmd(t, name, teamURL, avatarURL))) 61 require.True(t, te.engine.TeamExists(teamID1)) 62 63 require.EqualError(t, te.engine.CreateTeam(ctx, referrer2, teamID2, createTeamCmd(t, name, teamURL, avatarURL)), 64 teams.ErrTeamNameIsAlreadyInUse.Error(), 65 ) 66 } 67 68 func testAdministrateTeamSucceeds(t *testing.T) { 69 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomI64()) 70 71 te := newEngine(t) 72 73 require.False(t, te.engine.TeamExists(newTeamID(t))) 74 75 referrer1 := newPartyID(t) 76 teamID1 := newTeamID(t) 77 name := vgrand.RandomStr(5) 78 name2 := vgrand.RandomStr(5) 79 name3 := vgrand.RandomStr(5) 80 teamURL := "https://" + name + ".io" 81 avatarURL := "https://avatar." + name + ".io" 82 83 expectTeamCreatedEvent(t, te) 84 85 team1CreationDate := time.Now() 86 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1) 87 88 require.NoError(t, te.engine.CreateTeam(ctx, referrer1, teamID1, createTeamCmd(t, name, teamURL, avatarURL))) 89 require.True(t, te.engine.TeamExists(teamID1)) 90 91 assert.Equal(t, []types.Team{ 92 { 93 ID: teamID1, 94 Referrer: &types.Membership{ 95 PartyID: referrer1, 96 JoinedAt: team1CreationDate, 97 StartedAtEpoch: te.currentEpoch, 98 }, 99 Referees: nil, 100 Name: name, 101 TeamURL: teamURL, 102 AvatarURL: avatarURL, 103 CreatedAt: team1CreationDate, 104 Closed: false, 105 AllowList: nil, 106 }, 107 }, te.engine.ListTeams()) 108 109 referrer2 := newPartyID(t) 110 teamID2 := newTeamID(t) 111 112 expectTeamCreatedEvent(t, te) 113 114 team2CreationDate := time.Now() 115 te.timeService.EXPECT().GetTimeNow().Return(team2CreationDate).Times(1) 116 117 // Using same team URL and avatar URL as the first team is permitted. 118 require.NoError(t, te.engine.CreateTeam(ctx, referrer2, teamID2, createTeamCmd(t, name2, teamURL, avatarURL))) 119 require.True(t, te.engine.TeamExists(teamID2)) 120 assert.NotEqual(t, teamID1, teamID2, "Creating a team should generate an unique ID") 121 122 assertEqualTeams(t, []types.Team{ 123 { 124 ID: teamID1, 125 Referrer: &types.Membership{ 126 PartyID: referrer1, 127 JoinedAt: team1CreationDate, 128 StartedAtEpoch: te.currentEpoch, 129 }, 130 Name: name, 131 TeamURL: teamURL, 132 AvatarURL: avatarURL, 133 CreatedAt: team1CreationDate, 134 }, { 135 ID: teamID2, 136 Referrer: &types.Membership{ 137 PartyID: referrer2, 138 JoinedAt: team2CreationDate, 139 StartedAtEpoch: te.currentEpoch, 140 }, 141 Name: name2, 142 TeamURL: teamURL, 143 AvatarURL: avatarURL, 144 CreatedAt: team2CreationDate, 145 }, 146 }, te.engine.ListTeams()) 147 148 teamID3 := newTeamID(t) 149 150 // A party can only create one team. 151 require.EqualError(t, 152 te.engine.CreateTeam(ctx, referrer2, teamID3, createTeamCmd(t, name3, teamURL, avatarURL)), 153 teams.ErrPartyAlreadyBelongsToTeam(referrer2).Error(), 154 ) 155 156 assertEqualTeams(t, []types.Team{ 157 { 158 ID: teamID1, 159 Referrer: &types.Membership{ 160 PartyID: referrer1, 161 JoinedAt: team1CreationDate, 162 StartedAtEpoch: te.currentEpoch, 163 }, 164 Name: name, 165 TeamURL: teamURL, 166 AvatarURL: avatarURL, 167 CreatedAt: team1CreationDate, 168 }, { 169 ID: teamID2, 170 Referrer: &types.Membership{ 171 PartyID: referrer2, 172 JoinedAt: team2CreationDate, 173 StartedAtEpoch: te.currentEpoch, 174 }, 175 Name: name2, 176 TeamURL: teamURL, 177 AvatarURL: avatarURL, 178 CreatedAt: team2CreationDate, 179 }, 180 }, te.engine.ListTeams()) 181 182 referrer3 := newPartyID(t) 183 teamID4 := newTeamID(t) 184 185 expectTeamCreatedEvent(t, te) 186 187 team4CreationDate := time.Now() 188 te.timeService.EXPECT().GetTimeNow().Return(team4CreationDate).Times(1) 189 190 // Team URL and avatar URL are optional. 191 team4Name := vgrand.RandomStr(5) 192 require.NoError(t, te.engine.CreateTeam(ctx, referrer3, teamID4, createTeamCmd(t, team4Name, "", ""))) 193 require.True(t, te.engine.TeamExists(teamID4)) 194 assert.NotEqual(t, teamID1, teamID4, "Creating a team should generate an unique ID") 195 assert.NotEqual(t, teamID2, teamID4, "Creating a team should generate an unique ID") 196 197 assertEqualTeams(t, []types.Team{ 198 { 199 ID: teamID1, 200 Referrer: &types.Membership{ 201 PartyID: referrer1, 202 JoinedAt: team1CreationDate, 203 StartedAtEpoch: te.currentEpoch, 204 }, 205 Name: name, 206 TeamURL: teamURL, 207 AvatarURL: avatarURL, 208 CreatedAt: team1CreationDate, 209 }, { 210 ID: teamID2, 211 Referrer: &types.Membership{ 212 PartyID: referrer2, 213 JoinedAt: team2CreationDate, 214 StartedAtEpoch: te.currentEpoch, 215 }, 216 Name: name2, 217 TeamURL: teamURL, 218 AvatarURL: avatarURL, 219 CreatedAt: team2CreationDate, 220 }, { 221 ID: teamID4, 222 Referrer: &types.Membership{ 223 PartyID: referrer3, 224 JoinedAt: team4CreationDate, 225 StartedAtEpoch: te.currentEpoch, 226 }, 227 Referees: nil, 228 Name: team4Name, 229 TeamURL: "", 230 AvatarURL: "", 231 CreatedAt: team4CreationDate, 232 }, 233 }, te.engine.ListTeams()) 234 235 // Updating first team 236 updatedName := vgrand.RandomStr(5) 237 updatedTeamURL := "https://" + name + ".io" 238 updatedAvatarURL := "https://avatar." + name + ".io" 239 240 expectTeamUpdatedEvent(t, te) 241 242 require.NoError(t, te.engine.UpdateTeam(ctx, referrer1, teamID1, updateTeamCmd(t, updatedName, updatedTeamURL, updatedAvatarURL, false, nil))) 243 244 assertEqualTeams(t, []types.Team{ 245 { 246 ID: teamID1, 247 Referrer: &types.Membership{ 248 PartyID: referrer1, 249 JoinedAt: team1CreationDate, 250 StartedAtEpoch: te.currentEpoch, 251 }, 252 Name: updatedName, 253 TeamURL: updatedTeamURL, 254 AvatarURL: updatedAvatarURL, 255 CreatedAt: team1CreationDate, 256 }, { 257 ID: teamID2, 258 Referrer: &types.Membership{ 259 PartyID: referrer2, 260 JoinedAt: team2CreationDate, 261 StartedAtEpoch: te.currentEpoch, 262 }, 263 Name: name2, 264 TeamURL: teamURL, 265 AvatarURL: avatarURL, 266 CreatedAt: team2CreationDate, 267 }, { 268 ID: teamID4, 269 Referrer: &types.Membership{ 270 PartyID: referrer3, 271 JoinedAt: team4CreationDate, 272 StartedAtEpoch: te.currentEpoch, 273 }, 274 Name: team4Name, 275 TeamURL: "", 276 AvatarURL: "", 277 CreatedAt: team4CreationDate, 278 }, 279 }, te.engine.ListTeams()) 280 281 unknownTeamID := types.NewTeamID() 282 require.EqualError(t, 283 te.engine.UpdateTeam(ctx, referrer1, unknownTeamID, updateTeamCmd(t, updatedName, updatedTeamURL, updatedAvatarURL, false, nil)), 284 teams.ErrNoTeamMatchesID(unknownTeamID).Error(), 285 ) 286 287 require.ErrorIs(t, 288 teams.ErrOnlyReferrerCanUpdateTeam, 289 te.engine.UpdateTeam(ctx, referrer2, teamID1, updateTeamCmd(t, updatedName, updatedTeamURL, updatedAvatarURL, false, nil)), 290 ) 291 } 292 293 func testJoiningTeamSucceeds(t *testing.T) { 294 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomI64()) 295 296 te := newEngine(t) 297 298 team1CreationDate := time.Now() 299 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1) 300 teamID1, referrer1, team1Name := newTeam(t, ctx, te) 301 302 team2CreationDate := time.Now() 303 te.timeService.EXPECT().GetTimeNow().Return(team2CreationDate).Times(1) 304 teamID2, referrer2, team2Name := newTeam(t, ctx, te) 305 306 require.ErrorIs(t, te.engine.JoinTeam(ctx, referrer1, joinTeamCmd(t, teamID1)), teams.ErrReferrerCannotJoinAnotherTeam) 307 require.ErrorIs(t, te.engine.JoinTeam(ctx, referrer2, joinTeamCmd(t, teamID1)), teams.ErrReferrerCannotJoinAnotherTeam) 308 309 referee1 := newPartyID(t) 310 referee1JoiningDate := time.Now() 311 te.timeService.EXPECT().GetTimeNow().Return(referee1JoiningDate).Times(1) 312 expectRefereeJoinedTeamEvent(t, te) 313 require.NoError(t, te.engine.JoinTeam(ctx, referee1, joinTeamCmd(t, teamID1))) 314 require.True(t, te.engine.IsTeamMember(referee1)) 315 316 referee2 := newPartyID(t) 317 318 // referee2 tries to join a non-existing team. 319 unknownTeamID := types.NewTeamID() 320 require.EqualError(t, 321 te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, unknownTeamID)), 322 teams.ErrNoTeamMatchesID(unknownTeamID).Error(), 323 ) 324 require.False(t, te.engine.IsTeamMember(referee2)) 325 326 // referee2 joins an existing team. 327 expectRefereeJoinedTeamEvent(t, te) 328 referee2JoiningDate := time.Now() 329 te.timeService.EXPECT().GetTimeNow().Return(referee2JoiningDate).Times(1) 330 require.NoError(t, te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID1))) 331 require.True(t, te.engine.IsTeamMember(referee2)) 332 333 // referee2 just joined another team and want to move on next epoch. 334 require.NoError(t, te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID2))) 335 require.True(t, te.engine.IsTeamMember(referee2)) 336 337 // This shows the referee2 joined the first team he applied to, despite 338 // his second application to team 2. 339 assertEqualTeams(t, []types.Team{ 340 { 341 ID: teamID1, 342 Referrer: &types.Membership{ 343 PartyID: referrer1, 344 JoinedAt: team1CreationDate, 345 StartedAtEpoch: te.currentEpoch, 346 }, 347 Referees: []*types.Membership{ 348 { 349 PartyID: referee1, 350 JoinedAt: referee1JoiningDate, 351 StartedAtEpoch: te.currentEpoch, 352 }, { 353 PartyID: referee2, 354 JoinedAt: referee2JoiningDate, 355 StartedAtEpoch: te.currentEpoch, 356 }, 357 }, 358 Name: team1Name, 359 CreatedAt: team1CreationDate, 360 }, { 361 ID: teamID2, 362 Referrer: &types.Membership{ 363 PartyID: referrer2, 364 JoinedAt: team2CreationDate, 365 StartedAtEpoch: te.currentEpoch, 366 }, 367 Name: team2Name, 368 CreatedAt: team2CreationDate, 369 }, 370 }, te.engine.ListTeams()) 371 372 // Simulating moving to next epoch. 373 expectRefereeSwitchedTeamEvent(t, te) 374 referee2JoiningDate2 := time.Now() 375 nextEpoch(t, ctx, te, referee2JoiningDate2) 376 377 // This shows the referee2 moved from team 1 to team 2. 378 assertEqualTeams(t, []types.Team{ 379 { 380 ID: teamID1, 381 Referrer: &types.Membership{ 382 PartyID: referrer1, 383 JoinedAt: team1CreationDate, 384 StartedAtEpoch: te.currentEpoch - 1, 385 }, 386 Referees: []*types.Membership{ 387 { 388 PartyID: referee1, 389 JoinedAt: referee1JoiningDate, 390 StartedAtEpoch: te.currentEpoch - 1, 391 }, 392 }, 393 Name: team1Name, 394 CreatedAt: team1CreationDate, 395 }, { 396 ID: teamID2, 397 Referrer: &types.Membership{ 398 PartyID: referrer2, 399 JoinedAt: team2CreationDate, 400 StartedAtEpoch: te.currentEpoch - 1, 401 }, 402 Referees: []*types.Membership{ 403 { 404 PartyID: referee2, 405 JoinedAt: referee2JoiningDate2, 406 StartedAtEpoch: te.currentEpoch, 407 }, 408 }, 409 Name: team2Name, 410 CreatedAt: team2CreationDate, 411 }, 412 }, te.engine.ListTeams()) 413 414 // referee2 just re-joins team 1. 415 referee2JoiningDate3 := time.Now() 416 require.NoError(t, te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID1))) 417 require.True(t, te.engine.IsTeamMember(referee2)) 418 419 // Simulating moving to next epoch. 420 expectRefereeSwitchedTeamEvent(t, te) 421 nextEpoch(t, ctx, te, referee2JoiningDate3) 422 423 // This shows the referee2 moved from team 1 to team 2. 424 assertEqualTeams(t, []types.Team{ 425 { 426 ID: teamID1, 427 Referrer: &types.Membership{ 428 PartyID: referrer1, 429 JoinedAt: team1CreationDate, 430 StartedAtEpoch: te.currentEpoch - 2, 431 }, 432 Referees: []*types.Membership{ 433 { 434 PartyID: referee1, 435 JoinedAt: referee1JoiningDate, 436 StartedAtEpoch: te.currentEpoch - 2, 437 }, { 438 PartyID: referee2, 439 JoinedAt: referee2JoiningDate3, 440 StartedAtEpoch: te.currentEpoch, 441 }, 442 }, 443 Name: team1Name, 444 CreatedAt: team1CreationDate, 445 }, { 446 ID: teamID2, 447 Referrer: &types.Membership{ 448 PartyID: referrer2, 449 JoinedAt: team2CreationDate, 450 StartedAtEpoch: te.currentEpoch - 2, 451 }, 452 Referees: []*types.Membership{}, 453 Name: team2Name, 454 CreatedAt: team2CreationDate, 455 }, 456 }, te.engine.ListTeams()) 457 458 expectTeamUpdatedEvent(t, te) 459 460 // Closing the team. 461 require.NoError(t, te.engine.UpdateTeam(ctx, referrer2, teamID2, updateTeamCmd(t, "", "", "", true, nil))) 462 463 // referee2 try to re-join team 2, but joining a closed team without allow-list is disallow. 464 require.Error(t, te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID2))) 465 466 // Simulating moving to next epoch. 467 nextEpoch(t, ctx, te, referee2JoiningDate3) 468 469 // This shows the referee2 stayed in team 1. 470 assertEqualTeams(t, []types.Team{ 471 { 472 ID: teamID1, 473 Referrer: &types.Membership{ 474 PartyID: referrer1, 475 JoinedAt: team1CreationDate, 476 StartedAtEpoch: te.currentEpoch - 3, 477 }, 478 Referees: []*types.Membership{ 479 { 480 PartyID: referee1, 481 JoinedAt: referee1JoiningDate, 482 StartedAtEpoch: te.currentEpoch - 3, 483 }, { 484 PartyID: referee2, 485 JoinedAt: referee2JoiningDate3, 486 StartedAtEpoch: te.currentEpoch - 1, 487 }, 488 }, 489 Name: team1Name, 490 CreatedAt: team1CreationDate, 491 }, { 492 ID: teamID2, 493 Referrer: &types.Membership{ 494 PartyID: referrer2, 495 JoinedAt: team2CreationDate, 496 StartedAtEpoch: te.currentEpoch - 3, 497 }, 498 Referees: []*types.Membership{}, 499 Name: team2Name, 500 CreatedAt: team2CreationDate, 501 Closed: true, 502 }, 503 }, te.engine.ListTeams()) 504 505 // Allow referee2 to join the closed team. 506 expectTeamUpdatedEvent(t, te) 507 require.NoError(t, te.engine.UpdateTeam(ctx, referrer2, teamID2, updateTeamCmd(t, "", "", "", true, []string{referee2.String()}))) 508 509 // referee2 can re-join team 2, because that party is specified in allow-list. 510 require.NoError(t, te.engine.JoinTeam(ctx, referee2, joinTeamCmd(t, teamID2))) 511 512 // Simulating moving to next epoch. 513 expectRefereeSwitchedTeamEvent(t, te) 514 nextEpoch(t, ctx, te, referee2JoiningDate3) 515 516 // This shows the referee2 moved to team 2. 517 assertEqualTeams(t, []types.Team{ 518 { 519 ID: teamID1, 520 Referrer: &types.Membership{ 521 PartyID: referrer1, 522 JoinedAt: team1CreationDate, 523 StartedAtEpoch: te.currentEpoch - 4, 524 }, 525 Referees: []*types.Membership{ 526 { 527 PartyID: referee1, 528 JoinedAt: referee1JoiningDate, 529 StartedAtEpoch: te.currentEpoch - 4, 530 }, 531 }, 532 Name: team1Name, 533 CreatedAt: team1CreationDate, 534 }, { 535 ID: teamID2, 536 Referrer: &types.Membership{ 537 PartyID: referrer2, 538 JoinedAt: team2CreationDate, 539 StartedAtEpoch: te.currentEpoch - 4, 540 }, 541 Referees: []*types.Membership{ 542 { 543 PartyID: referee2, 544 JoinedAt: referee2JoiningDate3, 545 StartedAtEpoch: te.currentEpoch, 546 }, 547 }, 548 Name: team2Name, 549 CreatedAt: team2CreationDate, 550 Closed: true, 551 AllowList: []types.PartyID{referee2}, 552 }, 553 }, te.engine.ListTeams()) 554 555 // referee1 cannot join team 2, because that party is not specified in allow-list. 556 require.Error(t, te.engine.JoinTeam(ctx, referee1, joinTeamCmd(t, teamID2))) 557 558 // Simulating moving to next epoch. 559 nextEpoch(t, ctx, te, referee2JoiningDate3) 560 561 // This shows the referee1 did not moved to team 2. 562 assertEqualTeams(t, []types.Team{ 563 { 564 ID: teamID1, 565 Referrer: &types.Membership{ 566 PartyID: referrer1, 567 JoinedAt: team1CreationDate, 568 StartedAtEpoch: te.currentEpoch - 5, 569 }, 570 Referees: []*types.Membership{ 571 { 572 PartyID: referee1, 573 JoinedAt: referee1JoiningDate, 574 StartedAtEpoch: te.currentEpoch - 5, 575 }, 576 }, 577 Name: team1Name, 578 CreatedAt: team1CreationDate, 579 }, { 580 ID: teamID2, 581 Referrer: &types.Membership{ 582 PartyID: referrer2, 583 JoinedAt: team2CreationDate, 584 StartedAtEpoch: te.currentEpoch - 5, 585 }, 586 Referees: []*types.Membership{ 587 { 588 PartyID: referee2, 589 JoinedAt: referee2JoiningDate3, 590 StartedAtEpoch: te.currentEpoch - 1, 591 }, 592 }, 593 Name: team2Name, 594 CreatedAt: team2CreationDate, 595 Closed: true, 596 AllowList: []types.PartyID{referee2}, 597 }, 598 }, te.engine.ListTeams()) 599 600 referee4 := newPartyID(t) 601 602 team3CreationDate := time.Now() 603 te.timeService.EXPECT().GetTimeNow().Return(team3CreationDate).Times(1) 604 team3Name := vgrand.RandomStr(5) 605 teamID3, referrer3 := newTeamWithCmd(t, ctx, te, &commandspb.CreateReferralSet_Team{ 606 Name: team3Name, 607 Closed: true, 608 AllowList: []string{referee4.String()}, 609 }) 610 611 expectRefereeJoinedTeamEvent(t, te) 612 referee4JoiningDate := time.Now() 613 te.timeService.EXPECT().GetTimeNow().Return(referee4JoiningDate).Times(1) 614 require.NoError(t, te.engine.JoinTeam(ctx, referee4, joinTeamCmd(t, teamID3))) 615 require.True(t, te.engine.IsTeamMember(referee4)) 616 617 // This shows the referee1 did not moved to team 2. 618 assertEqualTeams(t, []types.Team{ 619 { 620 ID: teamID1, 621 Referrer: &types.Membership{ 622 PartyID: referrer1, 623 JoinedAt: team1CreationDate, 624 StartedAtEpoch: te.currentEpoch - 5, 625 }, 626 Referees: []*types.Membership{ 627 { 628 PartyID: referee1, 629 JoinedAt: referee1JoiningDate, 630 StartedAtEpoch: te.currentEpoch - 5, 631 }, 632 }, 633 Name: team1Name, 634 CreatedAt: team1CreationDate, 635 }, { 636 ID: teamID2, 637 Referrer: &types.Membership{ 638 PartyID: referrer2, 639 JoinedAt: team2CreationDate, 640 StartedAtEpoch: te.currentEpoch - 5, 641 }, 642 Referees: []*types.Membership{ 643 { 644 PartyID: referee2, 645 JoinedAt: referee2JoiningDate3, 646 StartedAtEpoch: te.currentEpoch - 1, 647 }, 648 }, 649 Name: team2Name, 650 CreatedAt: team2CreationDate, 651 Closed: true, 652 AllowList: []types.PartyID{referee2}, 653 }, { 654 ID: teamID3, 655 Referrer: &types.Membership{ 656 PartyID: referrer3, 657 JoinedAt: team3CreationDate, 658 StartedAtEpoch: te.currentEpoch, 659 }, 660 Referees: []*types.Membership{ 661 { 662 PartyID: referee4, 663 JoinedAt: referee4JoiningDate, 664 StartedAtEpoch: te.currentEpoch, 665 }, 666 }, 667 Name: team3Name, 668 CreatedAt: team3CreationDate, 669 Closed: true, 670 AllowList: []types.PartyID{referee4}, 671 }, 672 }, te.engine.ListTeams()) 673 } 674 675 func testMinEpochsRequired(t *testing.T) { 676 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomI64()) 677 678 te := newEngine(t) 679 680 team1CreationDate := time.Now() 681 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1) 682 teamID1, _, _ := newTeam(t, ctx, te) 683 684 // if we set min epochs to 0 then we see the referrer 685 members := te.engine.GetTeamMembers(string(teamID1), 0) 686 assert.Len(t, members, 1) 687 688 // referrer made a team, but does not get returned as a team member until its been the minimum epochs 689 members = te.engine.GetTeamMembers(string(teamID1), 5) 690 assert.Len(t, members, 0) 691 692 // move to epoch 11 and add a team member 693 te.engine.OnEpoch(ctx, types.Epoch{Seq: 11, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 694 695 expectRefereeJoinedTeamEvent(t, te) 696 referee := newPartyID(t) 697 refereeJoiningDate := time.Now() 698 te.timeService.EXPECT().GetTimeNow().Return(refereeJoiningDate).Times(1) 699 require.NoError(t, te.engine.JoinTeam(ctx, referee, joinTeamCmd(t, teamID1))) 700 701 // referrer joined at epoch 10, team member at 11 lets move to epoch 15 702 te.engine.OnEpoch(ctx, types.Epoch{Seq: 15, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 703 members = te.engine.GetTeamMembers(string(teamID1), 5) 704 assert.Len(t, members, 1) 705 706 // now at epoch 16 both should be there 707 te.engine.OnEpoch(ctx, types.Epoch{Seq: 16, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 708 members = te.engine.GetTeamMembers(string(teamID1), 5) 709 assert.Len(t, members, 2) 710 } 711 712 func TestRemoveFromAllowListRemoveFromTheTeam(t *testing.T) { 713 ctx := vgtest.VegaContext(vgrand.RandomStr(5), vgtest.RandomI64()) 714 715 te := newEngine(t) 716 717 require.False(t, te.engine.TeamExists(newTeamID(t))) 718 719 referrer1 := newPartyID(t) 720 referee1 := newPartyID(t) 721 teamID1 := newTeamID(t) 722 name := vgrand.RandomStr(5) 723 teamURL := "https://" + name + ".io" 724 avatarURL := "https://avatar." + name + ".io" 725 726 // create the team 727 expectTeamCreatedEvent(t, te) 728 team1CreationDate := time.Now() 729 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate).Times(1) 730 731 te.engine.OnEpoch(ctx, types.Epoch{Seq: 1, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 732 733 require.NoError(t, te.engine.CreateTeam(ctx, referrer1, teamID1, 734 createTeamWithAllowListCmd(t, name, teamURL, avatarURL, true, []string{referee1.String()}))) 735 require.True(t, te.engine.TeamExists(teamID1)) 736 737 // referee join the team 738 expectRefereeJoinedTeamEvent(t, te) 739 te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate.Add(10 * time.Second)).Times(1) 740 741 require.NoError(t, te.engine.JoinTeam(ctx, referee1, joinTeamCmd(t, teamID1))) 742 require.True(t, te.engine.IsTeamMember(referee1)) 743 // two members in the team 744 assert.Len(t, te.engine.GetTeamMembers(string(teamID1), 0), 2) 745 746 te.engine.OnEpoch(ctx, types.Epoch{Seq: 2, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 747 748 // referrer update the team to remove all allowlisted parties 749 expectTeamUpdatedEvent(t, te) 750 // te.timeService.EXPECT().GetTimeNow().Return(team1CreationDate.Add(20 * time.Second)).Times(1) 751 require.NoError(t, te.engine.UpdateTeam(ctx, referrer1, teamID1, 752 updateTeamCmd(t, name, teamURL, avatarURL, true, []string{}))) 753 require.True(t, te.engine.TeamExists(teamID1)) 754 755 // move to the next epoch 756 expectRefereeSwitchedTeamEvent(t, te) 757 te.engine.OnEpoch(ctx, types.Epoch{Seq: 2, Action: vegapb.EpochAction_EPOCH_ACTION_START}) 758 require.False(t, te.engine.IsTeamMember(referee1)) 759 // only referrer is team member now 760 assert.Len(t, te.engine.GetTeamMembers(string(teamID1), 0), 1) 761 }