github.com/lino-network/lino@v0.6.11/x/developer/manager/manager_test.go (about) 1 package developer // To test private filed `storage` 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "path/filepath" 8 "testing" 9 "time" 10 11 codec "github.com/cosmos/cosmos-sdk/codec" 12 sdk "github.com/cosmos/cosmos-sdk/types" 13 "github.com/stretchr/testify/mock" 14 "github.com/stretchr/testify/suite" 15 16 "github.com/lino-network/lino/param" 17 mparam "github.com/lino-network/lino/param/mocks" 18 "github.com/lino-network/lino/testsuites" 19 "github.com/lino-network/lino/testutils" 20 linotypes "github.com/lino-network/lino/types" 21 maccount "github.com/lino-network/lino/x/account/mocks" 22 "github.com/lino-network/lino/x/developer/model" 23 "github.com/lino-network/lino/x/developer/types" 24 mprice "github.com/lino-network/lino/x/price/mocks" 25 mvote "github.com/lino-network/lino/x/vote/mocks" 26 votetypes "github.com/lino-network/lino/x/vote/types" 27 ) 28 29 var ( 30 storeKeyStr = "testStoreKey" 31 storeKey = sdk.NewKVStoreKey(storeKeyStr) 32 appTest = linotypes.AccountKey("testapp") 33 appDoesNotExists = linotypes.AccountKey("testapp-does-not-exist") 34 appWithoutIDA = linotypes.AccountKey("testapp-without-ida") 35 appHasRevokedIDA = linotypes.AccountKey("testapp-revoked-ida") 36 ) 37 38 type DeveloperDumper struct{} 39 40 func (dumper DeveloperDumper) NewDumper() *testutils.Dumper { 41 return model.NewDeveloperDumper(model.NewDeveloperStorage(storeKey)) 42 } 43 44 type DeveloperManagerSuite struct { 45 testsuites.GoldenTestSuite 46 manager DeveloperManager 47 mParamKeeper *mparam.ParamKeeper 48 mVoteKeeper *mvote.VoteKeeper 49 mAccountKeeper *maccount.AccountKeeper 50 mPriceKeeper *mprice.PriceKeeper 51 } 52 53 func NewDeveloperManagerSuite() *DeveloperManagerSuite { 54 return &DeveloperManagerSuite{ 55 GoldenTestSuite: testsuites.NewGoldenTestSuite(DeveloperDumper{}, storeKey), 56 } 57 } 58 59 func (suite *DeveloperManagerSuite) SetupTest() { 60 suite.mParamKeeper = new(mparam.ParamKeeper) 61 suite.mVoteKeeper = new(mvote.VoteKeeper) 62 suite.mAccountKeeper = new(maccount.AccountKeeper) 63 suite.mPriceKeeper = new(mprice.PriceKeeper) 64 suite.manager = NewDeveloperManager(storeKey, suite.mParamKeeper, suite.mVoteKeeper, suite.mAccountKeeper, suite.mPriceKeeper) 65 suite.SetupCtx(0, time.Unix(0, 0), storeKey) 66 } 67 68 func TestDeveloperManagerSuite(t *testing.T) { 69 suite.Run(t, NewDeveloperManagerSuite()) 70 } 71 72 func (suite *DeveloperManagerSuite) TestInitGenesis() { 73 testCases := []struct { 74 reservePoolAmount linotypes.Coin 75 name string 76 expected sdk.Error 77 expectedStore *model.ReservePool 78 }{ 79 { 80 name: "Success Valid Genesis", 81 reservePoolAmount: linotypes.NewCoin(sdk.NewInt(1)), 82 expected: nil, 83 expectedStore: &model.ReservePool{Total: linotypes.NewCoin(sdk.NewInt(1))}, 84 }, 85 { 86 name: "Fail Invalid Genesis negative reservePoolAmount", 87 reservePoolAmount: linotypes.NewCoin(sdk.NewInt(-1)), 88 expected: types.ErrInvalidReserveAmount(linotypes.NewCoin(sdk.NewInt(-1))), 89 expectedStore: nil, 90 }, 91 } 92 for _, c := range testCases { 93 suite.Run(c.name, func() { 94 suite.SetupCtx(0, time.Unix(0, 0), storeKey) 95 suite.Equal(c.expected, suite.manager.InitGenesis(suite.Ctx, c.reservePoolAmount)) 96 suite.Golden() 97 }) 98 } 99 } 100 101 func (suite *DeveloperManagerSuite) TestDoesDeveloperExist() { 102 devDeleted := linotypes.AccountKey("testapp-deleted") 103 testCases := []struct { 104 name string 105 username linotypes.AccountKey 106 expected bool 107 }{ 108 { 109 name: "Developer exists not deleted", 110 username: appTest, 111 expected: true, 112 }, 113 { 114 name: "Developer exist deleted", 115 username: devDeleted, 116 expected: false, 117 }, 118 { 119 name: "Developer does not exist", 120 username: appDoesNotExists, 121 expected: false, 122 }, 123 } 124 for _, c := range testCases { 125 suite.Run(c.name, func() { 126 suite.LoadState(false) 127 suite.Equal(c.expected, suite.manager.DoesDeveloperExist(suite.Ctx, c.username)) 128 suite.Golden() 129 suite.AssertStateUnchanged(false) 130 }) 131 } 132 } 133 134 func (suite *DeveloperManagerSuite) TestGetDeveloper() { 135 testCases := []struct { 136 name string 137 username linotypes.AccountKey 138 expected model.Developer 139 expectedErr sdk.Error 140 }{ 141 { 142 name: "Developer exists", 143 username: appTest, 144 expected: model.Developer{ 145 Username: appTest, 146 IsDeleted: false, 147 Deposit: linotypes.NewCoinFromInt64(0), 148 AppConsumption: linotypes.NewMiniDollar(0), 149 }, 150 expectedErr: nil, 151 }, 152 { 153 name: "Developer does not exist", 154 username: appDoesNotExists, 155 expected: model.Developer{}, 156 expectedErr: types.ErrDeveloperNotFound(), 157 }, 158 } 159 for _, c := range testCases { 160 suite.Run(c.name, func() { 161 suite.LoadState(false) 162 got, err := suite.manager.GetDeveloper(suite.Ctx, c.username) 163 suite.Equal(c.expectedErr, err) 164 suite.Equal(c.expected, got) 165 suite.Golden() 166 suite.AssertStateUnchanged(false) 167 }) 168 } 169 } 170 171 func (suite *DeveloperManagerSuite) TestGetLiveDeveloper() { 172 testCases := []struct { 173 name string 174 expected []model.Developer 175 }{ 176 { 177 name: "All developers", 178 expected: []model.Developer{ 179 { 180 Username: "test", 181 Deposit: linotypes.NewCoinFromInt64(0), 182 AppConsumption: linotypes.NewMiniDollar(0), 183 IsDeleted: false, 184 }, 185 }, 186 }, 187 } 188 for _, c := range testCases { 189 suite.Run(c.name, func() { 190 suite.LoadState(true) 191 suite.Equal(c.expected, suite.manager.GetLiveDevelopers(suite.Ctx)) 192 suite.Golden() 193 suite.AssertStateUnchanged(true) 194 }) 195 } 196 } 197 198 func (suite *DeveloperManagerSuite) TestRegisterDeveloper() { 199 username := linotypes.AccountKey("test_username") 200 duplicateUsername := linotypes.AccountKey("test") 201 userRoleUsername := linotypes.AccountKey("test2") 202 voterDuty := votetypes.DutyVoter 203 voterDutyErr := linotypes.NewError(linotypes.CodeTestDummyError, "") 204 invalidVoterDuty := votetypes.DutyApp 205 206 minDeposit := linotypes.NewCoinFromInt64(50) 207 params := param.DeveloperParam{ 208 DeveloperMinDeposit: minDeposit, 209 } 210 stake := linotypes.NewCoinFromInt64(100) 211 noEnoughStake := linotypes.NewCoinFromInt64(10) 212 testCases := []struct { 213 name string 214 username linotypes.AccountKey 215 website string 216 description string 217 appMetaData string 218 accountExist bool 219 voterDutyErr *sdk.Error 220 voterDuty *votetypes.VoterDuty 221 developerParam *param.DeveloperParam 222 developerParamError sdk.Error 223 voteLinoStake *linotypes.Coin 224 voteLinoStakeError sdk.Error 225 voteAssignDutyCalled bool 226 voteAssignDutyError sdk.Error 227 expected sdk.Error 228 }{ 229 { 230 name: "Fail Account does not exist", 231 accountExist: false, 232 username: username, 233 expected: types.ErrAccountNotFound(), 234 }, 235 { 236 name: "Fail Developer already exists", 237 accountExist: true, 238 username: duplicateUsername, 239 expected: types.ErrDeveloperAlreadyExist(duplicateUsername), 240 }, 241 { 242 name: "Fail Account is not a Voter", 243 accountExist: true, 244 voterDuty: nil, 245 voterDutyErr: &voterDutyErr, 246 username: username, 247 expected: types.ErrInvalidVoterDuty(), 248 }, 249 { 250 name: "Fail Account is not a Duty Voter", 251 accountExist: true, 252 voterDuty: &invalidVoterDuty, 253 username: username, 254 expected: types.ErrInvalidVoterDuty(), 255 }, 256 { 257 name: "Fail Account has user role", 258 accountExist: true, 259 voterDuty: &voterDuty, 260 username: userRoleUsername, 261 expected: types.ErrInvalidUserRole(), 262 }, 263 { 264 name: "Fail Error from paramHolder", 265 accountExist: true, 266 voterDuty: &voterDuty, 267 developerParam: ¶ms, 268 developerParamError: sdk.ErrInternal("test"), 269 username: username, 270 expected: sdk.ErrInternal("test"), 271 }, 272 { 273 name: "Fail Error from vote.GetLinoStake", 274 accountExist: true, 275 voterDuty: &voterDuty, 276 developerParam: ¶ms, 277 developerParamError: nil, 278 voteLinoStake: &stake, 279 voteLinoStakeError: sdk.ErrInternal("test linostake"), 280 username: username, 281 expected: sdk.ErrInternal("test linostake"), 282 }, 283 { 284 name: "Fail not enough stake", 285 accountExist: true, 286 voterDuty: &voterDuty, 287 developerParam: ¶ms, 288 developerParamError: nil, 289 voteLinoStake: &noEnoughStake, 290 voteLinoStakeError: nil, 291 username: username, 292 expected: types.ErrInsufficientDeveloperDeposit(), 293 }, 294 { 295 name: "Fail Error from vote.AssignDuty", 296 accountExist: true, 297 voterDuty: &voterDuty, 298 developerParam: ¶ms, 299 developerParamError: nil, 300 voteLinoStake: &stake, 301 voteLinoStakeError: nil, 302 voteAssignDutyCalled: true, 303 voteAssignDutyError: sdk.ErrInternal("test assign duty"), 304 username: username, 305 expected: sdk.ErrInternal("test assign duty"), 306 }, 307 { 308 name: "Success", 309 accountExist: true, 310 voterDuty: &voterDuty, 311 developerParam: ¶ms, 312 developerParamError: nil, 313 voteLinoStake: &stake, 314 voteAssignDutyCalled: true, 315 voteLinoStakeError: nil, 316 voteAssignDutyError: nil, 317 username: username, 318 website: "test website", 319 description: "test description", 320 appMetaData: "test meta", 321 expected: nil, 322 }, 323 } 324 for _, c := range testCases { 325 suite.Run(c.name, func() { 326 suite.LoadState(false) 327 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.username).Return(c.accountExist).Once() 328 if c.voterDuty != nil { 329 suite.mVoteKeeper.On("GetVoterDuty", mock.Anything, c.username).Return(*c.voterDuty, nil).Once() 330 } 331 if c.voterDutyErr != nil { 332 suite.mVoteKeeper.On("GetVoterDuty", mock.Anything, c.username).Return(voterDuty, *c.voterDutyErr).Once() 333 } 334 if c.developerParam != nil { 335 suite.mParamKeeper.On("GetDeveloperParam", mock.Anything).Return(c.developerParam, c.developerParamError).Once() 336 } 337 if c.voteLinoStake != nil { 338 suite.mVoteKeeper.On("GetLinoStake", mock.Anything, c.username).Return(*c.voteLinoStake, c.voteLinoStakeError).Once() 339 } 340 if c.voteAssignDutyCalled { 341 suite.mVoteKeeper.On("AssignDuty", mock.Anything, c.username, votetypes.DutyApp, params.DeveloperMinDeposit).Return(c.voteAssignDutyError).Once() 342 } 343 suite.Equal(c.expected, suite.manager.RegisterDeveloper(suite.Ctx, c.username, c.website, c.description, c.appMetaData)) 344 suite.mAccountKeeper.AssertExpectations(suite.T()) 345 suite.mVoteKeeper.AssertExpectations(suite.T()) 346 suite.mParamKeeper.AssertExpectations(suite.T()) 347 suite.Golden() 348 if c.expected != nil { 349 suite.AssertStateUnchanged(false) 350 } 351 }) 352 } 353 } 354 355 func (suite *DeveloperManagerSuite) TestUpdateDeveloper() { 356 username := linotypes.AccountKey("test") 357 usernameDoesNotExist := linotypes.AccountKey("test-no") 358 usernameDeleted := linotypes.AccountKey("test-deleted") 359 website := "test website" 360 description := "test description" 361 meta := "test meta" 362 testCases := []struct { 363 name string 364 username linotypes.AccountKey 365 expected sdk.Error 366 }{ 367 { 368 name: "Fail developer doesnt exist", 369 username: usernameDoesNotExist, 370 expected: types.ErrDeveloperNotFound(), 371 }, { 372 name: "Fail developer deleted", 373 username: usernameDeleted, 374 expected: types.ErrDeveloperNotFound(), 375 }, { 376 name: "Success", 377 username: username, 378 expected: nil, 379 }, 380 } 381 for _, c := range testCases { 382 suite.Run(c.name, func() { 383 suite.LoadState(false) 384 suite.Equal(c.expected, suite.manager.UpdateDeveloper(suite.Ctx, c.username, website, description, meta)) 385 suite.Golden() 386 if c.expected != nil { 387 suite.AssertStateUnchanged(false) 388 } 389 }) 390 } 391 } 392 393 func (suite *DeveloperManagerSuite) TestIssueIDA() { 394 app := linotypes.AccountKey("testapp") 395 appDoesNotExists := linotypes.AccountKey("testapp-does-not-exist") 396 appHasIDA := linotypes.AccountKey("testapp-has-ida") 397 idaName := "test-lemon" 398 var idaPrice int64 = 100 399 testCases := []struct { 400 name string 401 appName linotypes.AccountKey 402 expected sdk.Error 403 }{ 404 { 405 name: "Fail Developer doesnt exist", 406 appName: appDoesNotExists, 407 expected: types.ErrDeveloperNotFound(), 408 }, 409 { 410 name: "Fail Developer has already issued IDA", 411 appName: appHasIDA, 412 expected: types.ErrIDAIssuedBefore(), 413 }, 414 { 415 name: "Success", 416 appName: app, 417 expected: nil, 418 }, 419 } 420 for _, c := range testCases { 421 suite.Run(c.name, func() { 422 suite.LoadState(false) 423 suite.Equal(c.expected, suite.manager.IssueIDA(suite.Ctx, c.appName, idaName, idaPrice)) 424 suite.Golden() 425 if c.expected != nil { 426 suite.AssertStateUnchanged(false) 427 } 428 }) 429 } 430 } 431 432 func (suite *DeveloperManagerSuite) TestMintIDA() { 433 amount := linotypes.NewCoinFromInt64(1) 434 zeroMiniDollar := linotypes.NewMiniDollar(0) 435 validMiniDollar := linotypes.NewMiniDollar(1) 436 testCases := []struct { 437 name string 438 appName linotypes.AccountKey 439 amount linotypes.Coin 440 expected sdk.Error 441 coinToMiniDollar *linotypes.MiniDollar 442 minusCoinFromUserCalled bool 443 minusCoinFromUser sdk.Error 444 }{ 445 { 446 name: "Fail Developer doesnt exist", 447 appName: appDoesNotExists, 448 amount: amount, 449 expected: types.ErrDeveloperNotFound(), 450 }, 451 { 452 name: "Fail App doesnt have IDA", 453 appName: appWithoutIDA, 454 amount: amount, 455 expected: types.ErrIDANotFound(), 456 }, 457 { 458 name: "Fail App has revoked IDA", 459 appName: appHasRevokedIDA, 460 amount: amount, 461 expected: types.ErrIDARevoked(), 462 }, 463 { 464 name: "Fail priceCoinToMiniDollar returns 0", 465 appName: appTest, 466 amount: amount, 467 coinToMiniDollar: &zeroMiniDollar, 468 expected: types.ErrExchangeMiniDollarZeroAmount(), 469 }, 470 { 471 name: "Fail accMinusCoinFromUsername returns error", 472 appName: appTest, 473 amount: amount, 474 coinToMiniDollar: &validMiniDollar, 475 minusCoinFromUserCalled: true, 476 minusCoinFromUser: sdk.ErrInternal("minus coin from username failed"), 477 expected: sdk.ErrInternal("minus coin from username failed"), 478 }, 479 { 480 name: "Success", 481 appName: appTest, 482 amount: amount, 483 coinToMiniDollar: &validMiniDollar, 484 minusCoinFromUserCalled: true, 485 minusCoinFromUser: nil, 486 expected: nil, 487 }, 488 } 489 for _, c := range testCases { 490 suite.Run(c.name, func() { 491 if c.coinToMiniDollar != nil { 492 suite.mPriceKeeper.On("CoinToMiniDollar", mock.Anything, 493 c.amount).Return(*c.coinToMiniDollar, nil).Once() 494 } 495 if c.minusCoinFromUserCalled { 496 suite.mAccountKeeper.On("MoveToPool", mock.Anything, 497 linotypes.DevIDAReservePool, linotypes.NewAccOrAddrFromAcc(c.appName), 498 c.amount).Return(c.minusCoinFromUser).Once() 499 } 500 suite.LoadState(false) 501 suite.Equal(c.expected, suite.manager.MintIDA(suite.Ctx, c.appName, c.amount)) 502 suite.Golden() 503 if c.expected != nil { 504 suite.AssertStateUnchanged(false) 505 } 506 suite.mPriceKeeper.AssertExpectations(suite.T()) 507 suite.mAccountKeeper.AssertExpectations(suite.T()) 508 }) 509 } 510 } 511 512 func (suite *DeveloperManagerSuite) TestIDAConvertFromLino() { 513 amount := linotypes.NewCoinFromInt64(1) 514 // zeroMiniDollar := linotypes.NewMiniDollar(0) 515 validMiniDollar := linotypes.NewMiniDollar(1) 516 user1 := linotypes.AccountKey("user1") 517 testCases := []struct { 518 name string 519 appName linotypes.AccountKey 520 user linotypes.AccountKey 521 amount linotypes.Coin 522 expected sdk.Error 523 coinToMiniDollar *linotypes.MiniDollar 524 minusCoinFromUserCalled bool 525 minusCoinFromUser sdk.Error 526 }{ 527 { 528 name: "Fail Developer doesnt exist", 529 appName: appDoesNotExists, 530 user: user1, 531 amount: amount, 532 expected: types.ErrDeveloperNotFound(), 533 }, 534 { 535 name: "Fail App doesnt have IDA", 536 appName: appWithoutIDA, 537 user: user1, 538 amount: amount, 539 expected: types.ErrIDANotFound(), 540 }, 541 { 542 name: "Fail App has revoked IDA", 543 appName: appHasRevokedIDA, 544 user: user1, 545 amount: amount, 546 expected: types.ErrIDARevoked(), 547 }, 548 { 549 name: "Fail accMinusCoinFromUsername returns error", 550 appName: appTest, 551 user: user1, 552 amount: amount, 553 coinToMiniDollar: &validMiniDollar, 554 minusCoinFromUserCalled: true, 555 minusCoinFromUser: sdk.ErrInternal("minus coin from username failed"), 556 expected: sdk.ErrInternal("minus coin from username failed"), 557 }, 558 { 559 name: "Success", 560 appName: appTest, 561 user: user1, 562 amount: amount, 563 coinToMiniDollar: &validMiniDollar, 564 minusCoinFromUserCalled: true, 565 minusCoinFromUser: nil, 566 expected: nil, 567 }, 568 } 569 for _, c := range testCases { 570 suite.Run(c.name, func() { 571 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.user).Return(true).Maybe() 572 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.appName).Return(true).Maybe() 573 if c.minusCoinFromUserCalled { 574 suite.mAccountKeeper.On( 575 "MoveCoin", mock.Anything, 576 linotypes.NewAccOrAddrFromAcc(c.user), 577 linotypes.NewAccOrAddrFromAcc(c.appName), c.amount).Return(nil).Once() 578 } 579 if c.coinToMiniDollar != nil { 580 suite.mPriceKeeper.On("CoinToMiniDollar", mock.Anything, 581 c.amount).Return(*c.coinToMiniDollar, nil).Once() 582 } 583 if c.minusCoinFromUserCalled { 584 suite.mAccountKeeper.On("MoveToPool", mock.Anything, 585 linotypes.DevIDAReservePool, linotypes.NewAccOrAddrFromAcc(c.appName), 586 c.amount).Return(c.minusCoinFromUser).Once() 587 } 588 suite.LoadState(false) 589 suite.Equal(c.expected, suite.manager.IDAConvertFromLino( 590 suite.Ctx, c.user, c.appName, c.amount)) 591 suite.Golden() 592 if c.expected != nil { 593 suite.AssertStateUnchanged(false) 594 } 595 suite.mPriceKeeper.AssertExpectations(suite.T()) 596 suite.mAccountKeeper.AssertExpectations(suite.T()) 597 }) 598 } 599 } 600 601 func (suite *DeveloperManagerSuite) TestPrivateAppIDAMove() { 602 to := linotypes.AccountKey("to") 603 from := linotypes.AccountKey("from") 604 fromNotEnough := linotypes.AccountKey("from-not-enough") 605 fromUnauthed := linotypes.AccountKey("from-unauthed") 606 fromNotFound := linotypes.AccountKey("from-not-found") 607 toNotFound := linotypes.AccountKey("to-not-found") 608 amount := linotypes.NewMiniDollar(100) 609 testCases := []struct { 610 name string 611 app linotypes.AccountKey 612 from linotypes.AccountKey 613 to linotypes.AccountKey 614 amount linotypes.MiniDollar 615 expected sdk.Error 616 }{ 617 { 618 name: "Fail negative amount", 619 app: appTest, 620 from: from, 621 to: to, 622 amount: linotypes.NewMiniDollar(-1), 623 expected: linotypes.ErrInvalidIDAAmount(), 624 }, 625 { 626 name: "Fail from not found", 627 app: appTest, 628 from: fromNotFound, 629 to: to, 630 amount: amount, 631 expected: types.ErrNotEnoughIDA(), 632 }, 633 { 634 name: "Fail from unauthed", 635 app: appTest, 636 from: fromUnauthed, 637 to: to, 638 amount: amount, 639 expected: types.ErrIDAUnauthed(), 640 }, 641 { 642 name: "Fail from balance not enough", 643 app: appTest, 644 from: fromNotEnough, 645 to: to, 646 amount: amount, 647 expected: types.ErrNotEnoughIDA(), 648 }, 649 { 650 name: "Succ should add to existing to account bank", 651 app: appTest, 652 from: from, 653 to: to, 654 amount: amount, 655 expected: nil, 656 }, 657 { 658 name: "Succ should create new to account bank", 659 app: appTest, 660 from: from, 661 to: toNotFound, 662 amount: amount, 663 expected: nil, 664 }, 665 } 666 for _, c := range testCases { 667 suite.Run(c.name, func() { 668 suite.LoadState(false, "IDABasic") 669 suite.Equal(c.expected, suite.manager.appIDAMove(suite.Ctx, c.app, c.from, c.to, c.amount)) 670 suite.Golden() 671 if c.expected != nil { 672 suite.AssertStateUnchanged(false, "IDABasic") 673 } 674 }) 675 } 676 } 677 678 func (suite *DeveloperManagerSuite) TestAppTransferIDA() { 679 to := linotypes.AccountKey("to") 680 from := linotypes.AccountKey("from") 681 app1affiliated := linotypes.AccountKey("testapp-affiliated") 682 exists := true 683 doesntExists := false 684 amount := sdk.NewInt(1) 685 testCases := []struct { 686 name string 687 appName linotypes.AccountKey 688 signer linotypes.AccountKey 689 from linotypes.AccountKey 690 to linotypes.AccountKey 691 fromExists *bool 692 toExists *bool 693 expected sdk.Error 694 }{ 695 { 696 name: "Fail from and to both not sender", 697 appName: appTest, 698 signer: appTest, 699 from: from, 700 to: to, 701 expected: types.ErrInvalidTransferTarget(), 702 }, 703 { 704 name: "Fail App does not exist", 705 appName: appDoesNotExists, 706 signer: appDoesNotExists, 707 from: from, 708 to: appDoesNotExists, 709 expected: types.ErrDeveloperNotFound(), 710 }, 711 { 712 name: "Fail App doesnt have IDA", 713 appName: appWithoutIDA, 714 signer: appWithoutIDA, 715 from: from, 716 to: appWithoutIDA, 717 expected: types.ErrIDANotFound(), 718 }, 719 { 720 name: "Fail App has revoked IDA", 721 appName: appHasRevokedIDA, 722 signer: appHasRevokedIDA, 723 from: from, 724 to: appHasRevokedIDA, 725 expected: types.ErrIDARevoked(), 726 }, 727 { 728 name: "Fail from account doesnt exist", 729 appName: appTest, 730 signer: appTest, 731 from: from, 732 to: appTest, 733 fromExists: &doesntExists, 734 expected: types.ErrAccountNotFound(), 735 }, 736 { 737 name: "Fail to account doesnt exist", 738 appName: appTest, 739 signer: appTest, 740 from: from, 741 to: appTest, 742 fromExists: &exists, 743 toExists: &doesntExists, 744 expected: types.ErrAccountNotFound(), 745 }, 746 { 747 name: "Fail signer does not match", 748 appName: appTest, 749 signer: from, 750 from: from, 751 to: appTest, 752 fromExists: &exists, 753 toExists: &exists, 754 expected: types.ErrInvalidSigner(), 755 }, 756 { 757 name: "Success Transfer from App", 758 appName: appTest, 759 signer: appTest, 760 from: appTest, 761 to: to, 762 fromExists: &exists, 763 toExists: &exists, 764 expected: nil, 765 }, 766 { 767 name: "Success Transfer to App", 768 appName: appTest, 769 signer: appTest, 770 from: from, 771 to: appTest, 772 fromExists: &exists, 773 toExists: &exists, 774 expected: nil, 775 }, 776 { 777 name: "Success Transfer to App by affiliated", 778 appName: appTest, 779 signer: app1affiliated, 780 from: from, 781 to: appTest, 782 fromExists: &exists, 783 toExists: &exists, 784 expected: nil, 785 }, 786 } 787 for _, c := range testCases { 788 suite.Run(c.name, func() { 789 if c.fromExists != nil { 790 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.from).Return(*c.fromExists).Once() 791 } 792 if c.toExists != nil { 793 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.to).Return(*c.toExists).Once() 794 } 795 suite.LoadState(false, "IDABasic") 796 suite.Equal(c.expected, suite.manager.AppTransferIDA( 797 suite.Ctx, c.appName, c.signer, amount, c.from, c.to)) 798 suite.Golden() 799 if c.expected != nil { 800 suite.AssertStateUnchanged(false, "IDABasic") 801 } 802 suite.mAccountKeeper.AssertExpectations(suite.T()) 803 }) 804 } 805 } 806 807 func (suite *DeveloperManagerSuite) TestMoveIDA() { 808 to := linotypes.AccountKey("to") 809 from := linotypes.AccountKey("from") 810 fromNotEnough := linotypes.AccountKey("from-not-enough") 811 fromUnauthed := linotypes.AccountKey("from-unauthed") 812 fromNotFound := linotypes.AccountKey("from-not-found") 813 toNotFound := linotypes.AccountKey("to-not-found") 814 amount := linotypes.NewMiniDollar(100) 815 exists := true 816 doesntExists := false 817 testCases := []struct { 818 name string 819 app linotypes.AccountKey 820 from linotypes.AccountKey 821 to linotypes.AccountKey 822 amount linotypes.MiniDollar 823 fromExists *bool 824 toExists *bool 825 expected sdk.Error 826 }{ 827 { 828 name: "Fail Developer doesnt exist", 829 app: appDoesNotExists, 830 amount: amount, 831 expected: types.ErrDeveloperNotFound(), 832 }, 833 { 834 name: "Fail App doesnt have IDA", 835 app: appWithoutIDA, 836 amount: amount, 837 expected: types.ErrIDANotFound(), 838 }, 839 { 840 name: "Fail App has revoked IDA", 841 app: appHasRevokedIDA, 842 amount: amount, 843 expected: types.ErrIDARevoked(), 844 }, 845 { 846 name: "Fail from account doesnt exist", 847 app: appTest, 848 from: from, 849 to: appTest, 850 fromExists: &doesntExists, 851 expected: types.ErrAccountNotFound(), 852 }, 853 { 854 name: "Fail to account doesnt exist", 855 app: appTest, 856 from: from, 857 to: appTest, 858 fromExists: &exists, 859 toExists: &doesntExists, 860 expected: types.ErrAccountNotFound(), 861 }, 862 { 863 name: "Fail negative amount", 864 app: appTest, 865 from: from, 866 to: to, 867 fromExists: &exists, 868 toExists: &exists, 869 amount: linotypes.NewMiniDollar(-1), 870 expected: linotypes.ErrInvalidIDAAmount(), 871 }, 872 { 873 name: "Fail from bank not found", 874 app: appTest, 875 from: fromNotFound, 876 to: to, 877 amount: amount, 878 fromExists: &exists, 879 toExists: &exists, 880 expected: types.ErrNotEnoughIDA(), 881 }, 882 { 883 name: "Fail from bank unauthed", 884 app: appTest, 885 from: fromUnauthed, 886 to: to, 887 amount: amount, 888 fromExists: &exists, 889 toExists: &exists, 890 expected: types.ErrIDAUnauthed(), 891 }, 892 { 893 name: "Fail from bank balance not enough", 894 app: appTest, 895 from: fromNotEnough, 896 to: to, 897 amount: amount, 898 fromExists: &exists, 899 toExists: &exists, 900 expected: types.ErrNotEnoughIDA(), 901 }, 902 { 903 name: "Succes should add to existing to account bank", 904 app: appTest, 905 from: from, 906 to: to, 907 amount: amount, 908 fromExists: &exists, 909 toExists: &exists, 910 expected: nil, 911 }, 912 { 913 name: "Succes should create new to account bank", 914 app: appTest, 915 from: from, 916 to: toNotFound, 917 amount: amount, 918 fromExists: &exists, 919 toExists: &exists, 920 expected: nil, 921 }, 922 } 923 for _, c := range testCases { 924 suite.Run(c.name, func() { 925 if c.fromExists != nil { 926 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.from).Return(*c.fromExists).Once() 927 } 928 if c.toExists != nil { 929 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.to).Return(*c.toExists).Once() 930 } 931 suite.LoadState(false, "IDABasic") 932 suite.Equal(c.expected, suite.manager.MoveIDA(suite.Ctx, c.app, c.from, c.to, c.amount)) 933 suite.Golden() 934 if c.expected != nil { 935 suite.AssertStateUnchanged(false, "IDABasic") 936 } 937 suite.mAccountKeeper.AssertExpectations(suite.T()) 938 }) 939 } 940 } 941 942 // This also includes GetMiniIDAPrice and GetIDA since they are really simple 943 func (suite *DeveloperManagerSuite) TestPrivateValidAppIDA() { 944 zeroPrices := linotypes.NewMiniDollar(0) 945 zeroIDA := model.AppIDA{} 946 price := linotypes.NewMiniDollar(10000) 947 ida := model.AppIDA{ 948 App: appTest, 949 Name: "test-lemon", 950 MiniIDAPrice: price, 951 RevokeCoinPrice: zeroPrices, 952 } 953 testCases := []struct { 954 name string 955 app linotypes.AccountKey 956 expectedError sdk.Error 957 expectedPrice linotypes.MiniDollar 958 expectedIDA model.AppIDA 959 }{ 960 { 961 name: "Fail Developer doesnt exist", 962 app: appDoesNotExists, 963 expectedError: types.ErrDeveloperNotFound(), 964 expectedPrice: zeroPrices, 965 expectedIDA: zeroIDA, 966 }, 967 { 968 name: "Fail App doesnt have IDA", 969 app: appWithoutIDA, 970 expectedError: types.ErrIDANotFound(), 971 expectedPrice: zeroPrices, 972 expectedIDA: zeroIDA, 973 }, 974 { 975 name: "Fail App has revoked IDA", 976 app: appHasRevokedIDA, 977 expectedError: types.ErrIDARevoked(), 978 expectedPrice: zeroPrices, 979 expectedIDA: zeroIDA, 980 }, 981 { 982 name: "Success", 983 app: appTest, 984 expectedError: nil, 985 expectedPrice: price, 986 expectedIDA: ida, 987 }, 988 } 989 for _, c := range testCases { 990 suite.Run(c.name, func() { 991 suite.LoadState(false, "IDABasic") 992 var ida *model.AppIDA = nil 993 if c.expectedError == nil { 994 ida = &c.expectedIDA 995 } 996 i, e := suite.manager.validAppIDA(suite.Ctx, c.app) 997 suite.Equal(ida, i) 998 suite.Equal(c.expectedError, e) 999 price, e := suite.manager.GetMiniIDAPrice(suite.Ctx, c.app) 1000 suite.Equal(c.expectedPrice, price) 1001 suite.Equal(c.expectedError, e) 1002 id, e := suite.manager.GetIDA(suite.Ctx, c.app) 1003 suite.Equal(c.expectedIDA, id) 1004 suite.Equal(c.expectedError, e) 1005 suite.Golden() 1006 suite.AssertStateUnchanged(false, "IDABasic") 1007 }) 1008 } 1009 } 1010 1011 // This also tests GetIDABank 1012 func (suite *DeveloperManagerSuite) TestBurnIDA() { 1013 zeroCoin := linotypes.NewCoinFromInt64(0) 1014 coin := linotypes.NewCoinFromInt64(1) 1015 coinAmountMoreThanPool := linotypes.NewCoinFromInt64(11) 1016 used := linotypes.NewMiniDollar(100) 1017 userNotEnough := linotypes.AccountKey("from-not-enough") 1018 user := linotypes.AccountKey("from") 1019 amount := linotypes.NewMiniDollar(10000) 1020 exists := true 1021 noExists := false 1022 testCases := []struct { 1023 name string 1024 app linotypes.AccountKey 1025 user linotypes.AccountKey 1026 amount linotypes.MiniDollar 1027 expectedError sdk.Error 1028 expectedCoin linotypes.Coin 1029 accountExists *bool 1030 bought *linotypes.Coin 1031 used *linotypes.MiniDollar 1032 }{ 1033 { 1034 name: "Fail app does not exist", 1035 app: appDoesNotExists, 1036 user: user, 1037 amount: amount, 1038 expectedCoin: zeroCoin, 1039 expectedError: types.ErrDeveloperNotFound(), 1040 }, 1041 { 1042 name: "Fail user does not exist", 1043 app: appTest, 1044 user: user, 1045 amount: amount, 1046 expectedCoin: zeroCoin, 1047 accountExists: &noExists, 1048 expectedError: types.ErrAccountNotFound(), 1049 }, 1050 { 1051 name: "Fail user does not have enough mini dollar", 1052 app: appTest, 1053 user: userNotEnough, 1054 amount: amount, 1055 expectedCoin: zeroCoin, 1056 accountExists: &exists, 1057 expectedError: types.ErrNotEnoughIDA(), 1058 }, 1059 { 1060 name: "Fail cannot burn 0 coin", 1061 app: appTest, 1062 user: user, 1063 amount: amount, 1064 expectedCoin: zeroCoin, 1065 accountExists: &exists, 1066 expectedError: types.ErrBurnZeroIDA(), 1067 bought: &zeroCoin, 1068 used: &used, 1069 }, 1070 { 1071 name: "Fail burn amount more than reserve pool", 1072 app: appTest, 1073 user: user, 1074 amount: amount, 1075 expectedCoin: zeroCoin, 1076 accountExists: &exists, 1077 expectedError: types.ErrInsuffientReservePool(), 1078 bought: &coinAmountMoreThanPool, 1079 used: &used, 1080 }, 1081 { 1082 name: "Success", 1083 app: appTest, 1084 user: user, 1085 amount: amount, 1086 expectedCoin: coin, 1087 accountExists: &exists, 1088 expectedError: nil, 1089 bought: &coin, 1090 used: &used, 1091 }, 1092 } 1093 for _, c := range testCases { 1094 suite.Run(c.name, func() { 1095 if c.accountExists != nil { 1096 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.user).Return(*c.accountExists).Once() 1097 } 1098 if c.bought != nil { 1099 suite.mPriceKeeper.On("MiniDollarToCoin", mock.Anything, c.amount).Return(*c.bought, *c.used, nil).Once() 1100 } 1101 if c.expectedCoin.IsPositive() { 1102 suite.mAccountKeeper.On("MoveFromPool", mock.Anything, 1103 linotypes.DevIDAReservePool, linotypes.NewAccOrAddrFromAcc(c.user), 1104 c.expectedCoin).Return(nil).Once() 1105 } 1106 suite.LoadState(false, "IDABasic") 1107 coin, err := suite.manager.BurnIDA(suite.Ctx, c.app, c.user, c.amount) 1108 suite.Equal(c.expectedCoin, coin) 1109 suite.Equal(c.expectedError, err) 1110 suite.Golden() 1111 if c.expectedError != nil { 1112 suite.AssertStateUnchanged(false, "IDABasic") 1113 } 1114 suite.mAccountKeeper.AssertExpectations(suite.T()) 1115 suite.mPriceKeeper.AssertExpectations(suite.T()) 1116 }) 1117 } 1118 } 1119 1120 func (suite *DeveloperManagerSuite) TestGetIDABank() { 1121 zeroBank := model.IDABank{} 1122 user := linotypes.AccountKey("from") 1123 bank := model.IDABank{ 1124 Balance: linotypes.NewMiniDollar(100000), 1125 } 1126 exists := true 1127 noExists := false 1128 testCases := []struct { 1129 name string 1130 app linotypes.AccountKey 1131 user linotypes.AccountKey 1132 expectedError sdk.Error 1133 expectedBank model.IDABank 1134 accountExists *bool 1135 }{ 1136 { 1137 name: "Fail app does not exist", 1138 app: appDoesNotExists, 1139 user: user, 1140 expectedError: types.ErrDeveloperNotFound(), 1141 expectedBank: zeroBank, 1142 }, 1143 { 1144 name: "Fail user does not exist", 1145 app: appTest, 1146 user: user, 1147 accountExists: &noExists, 1148 expectedBank: zeroBank, 1149 expectedError: types.ErrAccountNotFound(), 1150 }, 1151 { 1152 name: "Success", 1153 app: appTest, 1154 user: user, 1155 accountExists: &exists, 1156 expectedBank: bank, 1157 expectedError: nil, 1158 }, 1159 } 1160 for _, c := range testCases { 1161 suite.Run(c.name, func() { 1162 if c.accountExists != nil { 1163 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.user).Return(*c.accountExists).Once() 1164 } 1165 suite.LoadState(false, "IDABasic") 1166 bank, err := suite.manager.GetIDABank(suite.Ctx, c.app, c.user) 1167 suite.Equal(c.expectedBank, bank) 1168 suite.Equal(c.expectedError, err) 1169 suite.Golden() 1170 suite.AssertStateUnchanged(false, "IDABasic") 1171 suite.mAccountKeeper.AssertExpectations(suite.T()) 1172 }) 1173 } 1174 } 1175 1176 func (suite *DeveloperManagerSuite) TestUpdateAffiliated() { 1177 t := true 1178 f := false 1179 username := linotypes.AccountKey("testuser") 1180 appMaxAffiliated := linotypes.AccountKey("testapp-max-affiliated") 1181 userAffiliated := linotypes.AccountKey("testuser-affiliated") 1182 userDeveloper := linotypes.AccountKey("testuser-developer") 1183 userDeactivate := linotypes.AccountKey("testuser-deactivate") 1184 voterDuty := votetypes.DutyVoter 1185 invalidVoterDuty := votetypes.DutyApp 1186 testCases := []struct { 1187 name string 1188 appName linotypes.AccountKey 1189 username linotypes.AccountKey 1190 activate bool 1191 expected sdk.Error 1192 accountExists *bool 1193 vote *votetypes.VoterDuty 1194 }{ 1195 { 1196 name: "Fail app doesnt exist", 1197 appName: appDoesNotExists, 1198 username: username, 1199 expected: types.ErrDeveloperNotFound(), 1200 }, 1201 { 1202 name: "Fail user doesnt exist", 1203 appName: appTest, 1204 username: username, 1205 accountExists: &f, 1206 expected: types.ErrAccountNotFound(), 1207 }, 1208 { 1209 name: "Fail max affiliated account reached", 1210 appName: appMaxAffiliated, 1211 username: username, 1212 accountExists: &t, 1213 expected: types.ErrMaxAffiliatedExceeded(), 1214 }, 1215 { 1216 name: "Fail activate user is already affiliated with some app", 1217 appName: appTest, 1218 username: userAffiliated, 1219 accountExists: &t, 1220 activate: t, 1221 expected: types.ErrInvalidAffiliatedAccount("is affiliated already"), 1222 }, 1223 { 1224 name: "Fail activate user is already a developer", 1225 appName: appTest, 1226 username: userDeveloper, 1227 accountExists: &t, 1228 activate: t, 1229 expected: types.ErrInvalidAffiliatedAccount("is/was developer"), 1230 }, 1231 { 1232 name: "Fail activate user has some other duty", 1233 appName: appTest, 1234 username: username, 1235 accountExists: &t, 1236 vote: &invalidVoterDuty, 1237 activate: t, 1238 expected: types.ErrInvalidAffiliatedAccount("on duty of something else"), 1239 }, 1240 { 1241 name: "Success activate", 1242 appName: appTest, 1243 username: username, 1244 accountExists: &t, 1245 vote: &voterDuty, 1246 activate: t, 1247 expected: nil, 1248 }, 1249 { 1250 name: "Fail deactivate user isnt affiliated with any app", 1251 appName: appTest, 1252 username: username, 1253 accountExists: &t, 1254 vote: &voterDuty, 1255 activate: f, 1256 expected: types.ErrInvalidUserRole(), 1257 }, 1258 { 1259 name: "Fail deactivate user has different affiliated account", 1260 appName: appTest, 1261 username: userAffiliated, 1262 accountExists: &t, 1263 vote: &voterDuty, 1264 activate: f, 1265 expected: types.ErrInvalidAffiliatedAccount("not affiliated account of provided app"), 1266 }, 1267 { 1268 name: "Success deactivate", 1269 appName: appTest, 1270 username: userDeactivate, 1271 accountExists: &t, 1272 vote: &voterDuty, 1273 activate: f, 1274 expected: nil, 1275 }, 1276 } 1277 for _, c := range testCases { 1278 suite.Run(c.name, func() { 1279 if c.accountExists != nil { 1280 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.username).Return(*c.accountExists).Once() 1281 } 1282 if c.vote != nil && c.activate { 1283 suite.mVoteKeeper.On("GetVoterDuty", mock.Anything, c.username).Return(*c.vote, nil).Once() 1284 } 1285 suite.LoadState(false, "AffiliatedBasic") 1286 suite.Equal(c.expected, suite.manager.UpdateAffiliated(suite.Ctx, c.appName, c.username, c.activate)) 1287 suite.Golden() 1288 if c.expected != nil { 1289 suite.AssertStateUnchanged(false, "AffiliatedBasic") 1290 } 1291 suite.mAccountKeeper.AssertExpectations(suite.T()) 1292 suite.mVoteKeeper.AssertExpectations(suite.T()) 1293 }) 1294 } 1295 } 1296 1297 func (suite *DeveloperManagerSuite) TestGetAffiliatingApp() { 1298 userDev := linotypes.AccountKey("testuser-developer") 1299 username := linotypes.AccountKey("testuser-affiliated") 1300 app := linotypes.AccountKey("testapp-a") 1301 usernameNotAf := linotypes.AccountKey("testuser") 1302 testCases := []struct { 1303 name string 1304 username linotypes.AccountKey 1305 expectedApp linotypes.AccountKey 1306 expectedError sdk.Error 1307 }{ 1308 { 1309 name: "Fail no affiliation found", 1310 username: usernameNotAf, 1311 expectedApp: "", 1312 expectedError: types.ErrInvalidUserRole(), 1313 }, 1314 { 1315 name: "Success is developer", 1316 username: userDev, 1317 expectedApp: userDev, 1318 expectedError: nil, 1319 }, 1320 { 1321 name: "Success found affiliated app", 1322 username: username, 1323 expectedApp: app, 1324 expectedError: nil, 1325 }, 1326 } 1327 for _, c := range testCases { 1328 suite.Run(c.name, func() { 1329 suite.LoadState(false, "AffiliatedBasic") 1330 app, err := suite.manager.GetAffiliatingApp(suite.Ctx, c.username) 1331 suite.Equal(c.expectedApp, app) 1332 suite.Equal(c.expectedError, err) 1333 suite.Golden() 1334 suite.AssertStateUnchanged(false, "AffiliatedBasic") 1335 }) 1336 } 1337 } 1338 1339 func (suite *DeveloperManagerSuite) TestGetAffiliated() { 1340 testCases := []struct { 1341 name string 1342 app linotypes.AccountKey 1343 expected []linotypes.AccountKey 1344 }{ 1345 { 1346 name: "Success developer doesnt exist", 1347 app: appDoesNotExists, 1348 expected: nil, 1349 }, 1350 { 1351 name: "Success get all affiliated account", 1352 app: appTest, 1353 expected: []linotypes.AccountKey{ 1354 linotypes.AccountKey("testuser-deactivate"), 1355 }, 1356 }, 1357 } 1358 for _, c := range testCases { 1359 suite.Run(c.name, func() { 1360 suite.LoadState(false, "AffiliatedBasic") 1361 suite.Equal(c.expected, suite.manager.GetAffiliated(suite.Ctx, c.app)) 1362 suite.Golden() 1363 suite.AssertStateUnchanged(false, "AffiliatedBasic") 1364 }) 1365 } 1366 } 1367 1368 func (suite *DeveloperManagerSuite) TestUpdateIDAAuth() { 1369 t := true 1370 f := false 1371 userAf := linotypes.AccountKey("testuser-affiliated") 1372 user := linotypes.AccountKey("testuser") 1373 testCases := []struct { 1374 name string 1375 app linotypes.AccountKey 1376 username linotypes.AccountKey 1377 active bool 1378 expected sdk.Error 1379 aExists *bool 1380 }{ 1381 { 1382 name: "Fail developer doesnt exist", 1383 app: appDoesNotExists, 1384 expected: types.ErrDeveloperNotFound(), 1385 }, 1386 { 1387 name: "Fail account doesnt exist", 1388 app: appTest, 1389 aExists: &f, 1390 expected: types.ErrAccountNotFound(), 1391 }, 1392 { 1393 name: "Fail user is affiliated account", 1394 app: appTest, 1395 username: userAf, 1396 aExists: &t, 1397 expected: types.ErrInvalidIDAAuth(), 1398 }, 1399 { 1400 name: "Fail bank already has the target active state", 1401 app: appTest, 1402 username: user, 1403 aExists: &t, 1404 active: true, 1405 expected: types.ErrInvalidIDAAuth(), 1406 }, 1407 { 1408 name: "Success", 1409 app: appTest, 1410 username: user, 1411 aExists: &t, 1412 active: false, 1413 expected: nil, 1414 }, 1415 } 1416 for _, c := range testCases { 1417 suite.Run(c.name, func() { 1418 if c.aExists != nil { 1419 suite.mAccountKeeper.On("DoesAccountExist", mock.Anything, c.username).Return(*c.aExists).Once() 1420 } 1421 suite.LoadState(false, "IDABasic") 1422 suite.Equal(c.expected, suite.manager.UpdateIDAAuth(suite.Ctx, c.app, c.username, c.active)) 1423 suite.Golden() 1424 if c.expected != nil { 1425 suite.AssertStateUnchanged(false, "IDABasic") 1426 } 1427 suite.mAccountKeeper.AssertExpectations(suite.T()) 1428 }) 1429 } 1430 } 1431 1432 func (suite *DeveloperManagerSuite) TestReportConsumption() { 1433 testCases := []struct { 1434 name string 1435 app linotypes.AccountKey 1436 consumption linotypes.MiniDollar 1437 expected sdk.Error 1438 }{ 1439 { 1440 name: "Fail developer doesnt exist", 1441 app: appDoesNotExists, 1442 expected: types.ErrDeveloperNotFound(), 1443 }, 1444 { 1445 name: "Success", 1446 app: appTest, 1447 consumption: linotypes.NewMiniDollar(10), 1448 expected: nil, 1449 }, 1450 } 1451 for _, c := range testCases { 1452 suite.Run(c.name, func() { 1453 suite.LoadState(false, "DeveloperBasic") 1454 suite.Equal(c.expected, suite.manager.ReportConsumption(suite.Ctx, c.app, c.consumption)) 1455 suite.Golden() 1456 if c.expected != nil { 1457 suite.AssertStateUnchanged(false, "DeveloperBasic") 1458 } 1459 }) 1460 } 1461 } 1462 1463 func (suite *DeveloperManagerSuite) TestMonthlyDistributeDevInflation() { 1464 zeroCoin := linotypes.NewCoinFromInt64(0) 1465 inflation := linotypes.NewCoinFromInt64(100) 1466 testCases := []struct { 1467 name string 1468 expected sdk.Error 1469 totalInflation *linotypes.Coin 1470 totalInflationError sdk.Error 1471 shares []linotypes.Coin 1472 addCoinError sdk.Error 1473 }{ 1474 { 1475 name: "Fail error get inflation pool", 1476 expected: sdk.ErrInternal(""), 1477 totalInflation: &zeroCoin, 1478 totalInflationError: sdk.ErrInternal(""), 1479 }, 1480 { 1481 name: "Fail error when move coin to account", 1482 expected: sdk.ErrInternal(""), 1483 totalInflation: &inflation, 1484 totalInflationError: nil, 1485 shares: []linotypes.Coin{ 1486 linotypes.NewCoinFromInt64(50), 1487 }, 1488 addCoinError: sdk.ErrInternal(""), 1489 }, 1490 { 1491 name: "Succ no developers", 1492 expected: nil, 1493 }, 1494 { 1495 name: "Success even distribution", 1496 expected: nil, 1497 totalInflation: &inflation, 1498 totalInflationError: nil, 1499 shares: []linotypes.Coin{ 1500 linotypes.NewCoinFromInt64(50), 1501 linotypes.NewCoinFromInt64(50), 1502 }, 1503 }, 1504 { 1505 name: "Success even distribution with remainder", 1506 expected: nil, 1507 totalInflation: &inflation, 1508 totalInflationError: nil, 1509 shares: []linotypes.Coin{ 1510 linotypes.NewCoinFromInt64(33), 1511 linotypes.NewCoinFromInt64(33), 1512 linotypes.NewCoinFromInt64(34), 1513 }, 1514 }, 1515 { 1516 name: "Success distribute according to consumption", 1517 expected: nil, 1518 totalInflation: &inflation, 1519 totalInflationError: nil, 1520 shares: []linotypes.Coin{ 1521 linotypes.NewCoinFromInt64(14), 1522 linotypes.NewCoinFromInt64(29), 1523 linotypes.NewCoinFromInt64(57), 1524 }, 1525 }, 1526 } 1527 for _, c := range testCases { 1528 suite.Run(c.name, func() { 1529 if c.totalInflation != nil { 1530 suite.mAccountKeeper.On("GetPool", 1531 mock.Anything, linotypes.InflationDeveloperPool).Return( 1532 *c.totalInflation, c.totalInflationError).Once() 1533 } 1534 for i, share := range c.shares { 1535 suite.mAccountKeeper.On("MoveFromPool", mock.Anything, 1536 linotypes.InflationDeveloperPool, 1537 linotypes.NewAccOrAddrFromAcc( 1538 linotypes.AccountKey(fmt.Sprintf("testapp-%d", i))), 1539 share).Return(c.addCoinError).Once() 1540 } 1541 suite.LoadState(true) 1542 suite.Equal(c.expected, suite.manager.MonthlyDistributeDevInflation(suite.Ctx)) 1543 suite.Golden() 1544 suite.mAccountKeeper.AssertExpectations(suite.T()) 1545 }) 1546 } 1547 } 1548 1549 func (suite *DeveloperManagerSuite) TestImportExport() { 1550 // background data 1551 suite.manager.storage.SetDeveloper(suite.Ctx, model.Developer{ 1552 Username: "app1", 1553 Deposit: linotypes.NewCoinFromInt64(0), 1554 AppConsumption: linotypes.NewMiniDollar(1234), 1555 Website: "web1", 1556 Description: "app1 is good", 1557 AppMetaData: "app1 meta", 1558 IsDeleted: false, 1559 NAffiliated: 233, 1560 }) 1561 suite.manager.storage.SetDeveloper(suite.Ctx, model.Developer{ 1562 Username: "app2", 1563 Deposit: linotypes.NewCoinFromInt64(0), 1564 AppConsumption: linotypes.NewMiniDollar(5678), 1565 Website: "web2", 1566 Description: "app2 is good", 1567 AppMetaData: "app2 meta", 1568 IsDeleted: true, 1569 NAffiliated: 567, 1570 }) 1571 suite.manager.storage.SetDeveloper(suite.Ctx, model.Developer{ 1572 Username: "app3", 1573 Deposit: linotypes.NewCoinFromInt64(0), 1574 AppConsumption: linotypes.NewMiniDollar(10), 1575 Website: "web3", 1576 Description: "app3 is good", 1577 AppMetaData: "app3 meta", 1578 IsDeleted: true, 1579 NAffiliated: 567, 1580 }) 1581 suite.manager.storage.SetIDA(suite.Ctx, model.AppIDA{ 1582 App: "app1", 1583 Name: "lemon", 1584 MiniIDAPrice: linotypes.NewMiniDollar(1234), 1585 IsRevoked: true, 1586 RevokeCoinPrice: linotypes.NewMiniDollar(556), 1587 }) 1588 suite.manager.storage.SetIDA(suite.Ctx, model.AppIDA{ 1589 App: "app2", 1590 Name: "candy", 1591 MiniIDAPrice: linotypes.NewMiniDollar(45), 1592 IsRevoked: false, 1593 RevokeCoinPrice: linotypes.NewMiniDollar(0), 1594 }) 1595 1596 suite.manager.storage.SetAffiliatedAcc(suite.Ctx, "app1", "user1") 1597 suite.manager.storage.SetAffiliatedAcc(suite.Ctx, "app1", "user2") 1598 suite.manager.storage.SetAffiliatedAcc(suite.Ctx, "app2", "user3") 1599 1600 suite.manager.storage.SetIDABank(suite.Ctx, "app1", "user1", &model.IDABank{ 1601 Balance: linotypes.NewMiniDollar(123), 1602 Unauthed: false, 1603 }) 1604 suite.manager.storage.SetIDABank(suite.Ctx, "app2", "user1", &model.IDABank{ 1605 Balance: linotypes.NewMiniDollar(456), 1606 Unauthed: false, 1607 }) 1608 suite.manager.storage.SetIDABank(suite.Ctx, "app1", "user2", &model.IDABank{ 1609 Balance: linotypes.NewMiniDollar(789), 1610 Unauthed: false, 1611 }) 1612 1613 suite.manager.storage.SetIDAStats(suite.Ctx, "app1", model.AppIDAStats{ 1614 Total: linotypes.NewMiniDollar(1000), 1615 }) 1616 suite.manager.storage.SetIDAStats(suite.Ctx, "app2", model.AppIDAStats{ 1617 Total: linotypes.NewMiniDollar(2000), 1618 }) 1619 1620 suite.manager.storage.SetUserRole(suite.Ctx, "user1", &model.Role{ 1621 AffiliatedApp: "app1", 1622 }) 1623 suite.manager.storage.SetUserRole(suite.Ctx, "user2", &model.Role{ 1624 AffiliatedApp: "app1", 1625 }) 1626 suite.manager.storage.SetUserRole(suite.Ctx, "user3", &model.Role{ 1627 AffiliatedApp: "app2", 1628 }) 1629 1630 suite.manager.storage.SetReservePool(suite.Ctx, &model.ReservePool{ 1631 Total: linotypes.NewCoinFromInt64(123), 1632 TotalMiniDollar: linotypes.NewMiniDollar(456), 1633 }) 1634 1635 cdc := codec.New() 1636 dir, err2 := ioutil.TempDir("", "test") 1637 suite.Require().Nil(err2) 1638 defer os.RemoveAll(dir) // clean up 1639 1640 tmpfn := filepath.Join(dir, "tmpfile") 1641 err2 = suite.manager.ExportToFile(suite.Ctx, cdc, tmpfn) 1642 suite.Nil(err2) 1643 1644 // reset all state. 1645 suite.SetupTest() 1646 err2 = suite.manager.ImportFromFile(suite.Ctx, cdc, tmpfn) 1647 suite.Nil(err2) 1648 1649 suite.Golden() 1650 }