From 44981582145e802c22d1816b50babe1999397857 Mon Sep 17 00:00:00 2001 From: Frojdi Dymylja <33157909+fdymylja@users.noreply.github.com> Date: Mon, 3 Aug 2020 10:41:40 +0200 Subject: [PATCH] enhance executors tests (#299) * chore: enhance executors tests * chore: update CHANGELOG.md * change: make controllers API nicer * chore: update CHANGELOG.md --- CHANGELOG.md | 2 + mock/configuration.go | 42 +++ x/starname/account_handlers.go | 123 ++++---- x/starname/controllers/account/account.go | 293 ++++++++++-------- .../controllers/account/account_test.go | 46 +-- x/starname/controllers/domain/domain.go | 133 ++++---- x/starname/controllers/domain/domain_test.go | 10 +- x/starname/domain_handlers.go | 41 ++- x/starname/keeper/executor/account_test.go | 137 ++++++++ x/starname/keeper/executor/domain_test.go | 41 +++ x/starname/keeper/executor/main_test.go | 45 ++- 11 files changed, 612 insertions(+), 301 deletions(-) create mode 100644 mock/configuration.go create mode 100644 x/starname/keeper/executor/account_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a1ca1a5..a32f2e23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## HEAD +- make controllers API nicer +- enhance executors tests - allow open domain transfers - fix filtering when primary key is present - fix finding the smallest set in the filters diff --git a/mock/configuration.go b/mock/configuration.go new file mode 100644 index 00000000..5efb6189 --- /dev/null +++ b/mock/configuration.go @@ -0,0 +1,42 @@ +package mock + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/iov-one/iovns/x/configuration" + "time" +) + +type Configuration struct { + fees *configuration.Fees + conf *configuration.Config +} + +func NewConfiguration(fees *configuration.Fees, conf *configuration.Config) Configuration { + return Configuration{ + fees: fees, + conf: conf, + } +} +func (c Configuration) GetFees(_ sdk.Context) *configuration.Fees { + return c.fees +} + +func (c Configuration) GetConfiguration(_ sdk.Context) configuration.Config { + return *c.conf +} + +func (c Configuration) IsOwner(_ sdk.Context, addr sdk.AccAddress) bool { + return c.conf.Configurer.Equals(addr) +} + +func (c Configuration) GetValidDomainNameRegexp(_ sdk.Context) string { + return c.conf.ValidDomainName +} + +func (c Configuration) GetDomainRenewDuration(_ sdk.Context) time.Duration { + return c.conf.DomainRenewalPeriod +} + +func (c Configuration) GetDomainGracePeriod(c_ sdk.Context) time.Duration { + return c.conf.DomainGracePeriod +} diff --git a/x/starname/account_handlers.go b/x/starname/account_handlers.go index 4540bd76..edd9ec94 100644 --- a/x/starname/account_handlers.go +++ b/x/starname/account_handlers.go @@ -16,7 +16,10 @@ import ( func handlerMsgAddAccountCertificates(ctx sdk.Context, k keeper.Keeper, msg *types.MsgAddAccountCertificates) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate(domain.MustExist, domain.NotExpired); err != nil { + if err := domainCtrl. + MustExist(). + NotExpired(). + Validate(); err != nil { return nil, err } @@ -24,14 +27,14 @@ func handlerMsgAddAccountCertificates(ctx sdk.Context, k keeper.Keeper, msg *typ accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name). WithDomainController(domainCtrl) - if err := accountCtrl.Validate( - account.MustExist, - account.NotExpired, - account.Owner(msg.Owner), - account.CertificateLimitNotExceeded, - account.CertificateSizeNotExceeded(msg.NewCertificate), - account.CertificateNotExist(msg.NewCertificate), - ); err != nil { + if err := accountCtrl. + MustExist(). + NotExpired(). + OwnedBy(msg.Owner). + CertificateLimitNotExceeded(). + CertificateSizeNotExceeded(msg.NewCertificate). + CertificateNotExist(msg.NewCertificate). + Validate(); err != nil { return nil, err } feeCtrl := fees.NewController(ctx, k, domainCtrl.Domain()) @@ -51,21 +54,21 @@ func handlerMsgAddAccountCertificates(ctx sdk.Context, k keeper.Keeper, msg *typ func handlerMsgDeleteAccountCertificate(ctx sdk.Context, k keeper.Keeper, msg *types.MsgDeleteAccountCertificate) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate( - domain.MustExist, - domain.NotExpired, - ); err != nil { + if err := domainCtrl. + MustExist(). + NotExpired(). + Validate(); err != nil { return nil, err } // perform account checks, save certificate index accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name) certIndex := new(int) - if err := accountCtrl.Validate( - account.MustExist, - account.NotExpired, - account.Owner(msg.Owner), - account.CertificateExists(msg.DeleteCertificate, certIndex), - ); err != nil { + if err := accountCtrl. + MustExist(). + NotExpired(). + OwnedBy(msg.Owner). + CertificateExists(msg.DeleteCertificate, certIndex). + Validate(); err != nil { return nil, err } feeCtrl := fees.NewController(ctx, k, domainCtrl.Domain()) @@ -86,13 +89,16 @@ func handlerMsgDeleteAccountCertificate(ctx sdk.Context, k keeper.Keeper, msg *t func handlerMsgDeleteAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgDeleteAccount) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate(domain.MustExist); err != nil { + if err := domainCtrl.MustExist().Validate(); err != nil { return nil, err } // perform account checks accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name). WithDomainController(domainCtrl) - if err := accountCtrl.Validate(account.MustExist, account.DeletableBy(msg.Owner)); err != nil { + if err := accountCtrl. + MustExist(). + DeletableBy(msg.Owner). + Validate(); err != nil { return nil, err } // collect fees @@ -114,21 +120,21 @@ func handlerMsgDeleteAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgDel func handleMsgRegisterAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgRegisterAccount) (*sdk.Result, error) { conf := k.ConfigurationKeeper.GetConfiguration(ctx) domainCtrl := domain.NewController(ctx, k, msg.Domain).WithConfiguration(conf) - if err := domainCtrl.Validate( - domain.MustExist, - domain.NotExpired, - ); err != nil { + if err := domainCtrl. + MustExist(). + NotExpired(). + Validate(); err != nil { return nil, err } d := domainCtrl.Domain() accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name). WithDomainController(domainCtrl) - if err := accountCtrl.Validate( - account.ValidName, - account.MustNotExist, - account.ValidResources(msg.Resources), - account.RegistrableBy(msg.Registerer), - ); err != nil { + if err := accountCtrl. + ValidName(). + MustNotExist(). + ValidResources(msg.Resources). + RegistrableBy(msg.Registerer). + Validate(); err != nil { return nil, err } @@ -162,14 +168,15 @@ func handlerMsgRenewAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgRene conf := k.ConfigurationKeeper.GetConfiguration(ctx) // validate domain domainCtrl := domain.NewController(ctx, k, msg.Domain).WithConfiguration(conf) - if err := domainCtrl.Validate(domain.MustExist, domain.Type(types.OpenDomain)); err != nil { + if err := domainCtrl.MustExist().Type(types.OpenDomain).Validate(); err != nil { return nil, err } // validate account accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name).WithConfiguration(conf) - if err := accountCtrl.Validate( - account.MustExist, - account.Renewable); err != nil { + if err := accountCtrl. + MustExist(). + Renewable(). + Validate(); err != nil { return nil, err } feeCtrl := fees.NewController(ctx, k, domainCtrl.Domain()) @@ -200,18 +207,18 @@ func handlerMsgRenewAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgRene func handlerMsgReplaceAccountResources(ctx sdk.Context, k keeper.Keeper, msg *types.MsgReplaceAccountResources) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate(domain.MustExist, domain.NotExpired); err != nil { + if err := domainCtrl.MustExist().NotExpired().Validate(); err != nil { return nil, err } // perform account checks accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name) - if err := accountCtrl.Validate( - account.MustExist, - account.NotExpired, - account.Owner(msg.Owner), - account.ValidResources(msg.NewResources), - account.ResourceLimitNotExceeded(msg.NewResources), - ); err != nil { + if err := accountCtrl. + MustExist(). + NotExpired(). + OwnedBy(msg.Owner). + ValidResources(msg.NewResources). + ResourceLimitNotExceeded(msg.NewResources). + Validate(); err != nil { return nil, err } feeCtrl := fees.NewController(ctx, k, domainCtrl.Domain()) @@ -232,16 +239,17 @@ func handlerMsgReplaceAccountResources(ctx sdk.Context, k keeper.Keeper, msg *ty func handlerMsgReplaceAccountMetadata(ctx sdk.Context, k keeper.Keeper, msg *types.MsgReplaceAccountMetadata) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate(domain.MustExist, domain.NotExpired); err != nil { + if err := domainCtrl.MustExist().NotExpired().Validate(); err != nil { return nil, err } // perform account checks accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name) - if err := accountCtrl.Validate( - account.MustExist, - account.NotExpired, - account.Owner(msg.Owner), - account.MetadataSizeNotExceeded(msg.NewMetadataURI)); err != nil { + if err := accountCtrl. + MustExist(). + NotExpired(). + OwnedBy(msg.Owner). + MetadataSizeNotExceeded(msg.NewMetadataURI). + Validate(); err != nil { return nil, err } // collect fees @@ -264,21 +272,18 @@ func handlerMsgReplaceAccountMetadata(ctx sdk.Context, k keeper.Keeper, msg *typ func handlerMsgTransferAccount(ctx sdk.Context, k keeper.Keeper, msg *types.MsgTransferAccount) (*sdk.Result, error) { // perform domain checks domainCtrl := domain.NewController(ctx, k, msg.Domain) - if err := domainCtrl.Validate( - domain.MustExist, - domain.NotExpired, - ); err != nil { + if err := domainCtrl.MustExist().NotExpired().Validate(); err != nil { return nil, err } // check if account exists accountCtrl := account.NewController(ctx, k, msg.Domain, msg.Name). WithDomainController(domainCtrl) - if err := accountCtrl.Validate( - account.MustExist, - account.NotExpired, - account.TransferableBy(msg.Owner), - account.ResettableBy(msg.Owner, msg.Reset), - ); err != nil { + if err := accountCtrl. + MustExist(). + NotExpired(). + TransferableBy(msg.Owner). + ResettableBy(msg.Owner, msg.Reset). + Validate(); err != nil { return nil, err } diff --git a/x/starname/controllers/account/account.go b/x/starname/controllers/account/account.go index d19c731c..1b8abd33 100644 --- a/x/starname/controllers/account/account.go +++ b/x/starname/controllers/account/account.go @@ -16,8 +16,8 @@ import ( "github.com/iov-one/iovns/x/starname/types" ) -// ControllerFunc is the function signature used by account controllers -type ControllerFunc func(ctrl *Account) error +// accountControllerFunc is the function signature used by account controllers +type accountControllerFunc func(ctrl *Account) error // Account is an account controller, it caches information // in order to avoid useless query to state to get the same @@ -26,6 +26,8 @@ type ControllerFunc func(ctrl *Account) error // panic because of bad operation flow. // Errors returned are wrapped sdk.Error types. type Account struct { + validators []accountControllerFunc + name, domain string account *types.Account conf *configuration.Config @@ -36,6 +38,155 @@ type Account struct { domainCtrl *domain.Domain } +// Validate verifies the account against the order of provided controllers +func (a *Account) Validate() error { + for _, check := range a.validators { + if err := check(a); err != nil { + return err + } + } + return nil +} + +// MustExist asserts that the given account exists +func (a *Account) MustExist() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.mustExist() + }) + return a +} + +// MustNotExist asserts that the given account does not exist +func (a *Account) MustNotExist() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.mustNotExist() + }) + return a +} + +func (a *Account) ValidName() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return a.validName() + }) + return a +} + +func (a *Account) NotExpired() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.notExpired() + }) + return a +} + +func (a *Account) Renewable() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.renewable() + }) + return a +} + +func (a *Account) OwnedBy(addr sdk.AccAddress) *Account { + f := func(ctrl *Account) error { + return ctrl.ownedBy(addr) + } + a.validators = append(a.validators, f) + return a +} + +func (a *Account) CertificateSizeNotExceeded(cert []byte) *Account { + f := func(ctrl *Account) error { + return ctrl.certSizeNotExceeded(cert) + } + a.validators = append(a.validators, f) + return a +} + +func (a *Account) CertificateLimitNotExceeded() *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.certLimitNotExceeded() + }) + return a +} + +// DeletableBy checks if the account can be deleted by the provided address +func (a *Account) DeletableBy(addr sdk.AccAddress) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.deletableBy(addr) + }) + return a +} + +// CertificateExists asserts that the provided certificate +// exists and if it does the index is saved in the provided pointer +// if certIndex pointer is nil the certificate index will not be saved +func (a *Account) CertificateExists(cert []byte, certIndex *int) *Account { + f := func(ctrl *Account) error { + err := ctrl.certNotExist(cert, certIndex) + if err == nil { + return sdkerrors.Wrapf(types.ErrCertificateDoesNotExist, "%x", cert) + } + return nil + } + a.validators = append(a.validators, f) + return a +} + +// ValidResources verifies that the provided resources are valid for the account +func (a *Account) ValidResources(resources []types.Resource) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.validResources(resources) + }) + return a +} + +// TransferableBy checks if the account can be transferred by the provided address +func (a *Account) TransferableBy(addr sdk.AccAddress) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.transferableBy(addr) + }) + return a +} + +// ResettableBy checks if the account attributes resettable by the provided address +func (a *Account) ResettableBy(addr sdk.AccAddress, reset bool) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.resettableBy(addr, reset) + }) + return a +} + +// ResettableBy checks if the account attributes resettable by the provided address +func (a *Account) ResourceLimitNotExceeded(resources []types.Resource) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.resourceLimitNotExceeded(resources) + }) + return a +} + +func (a *Account) MetadataSizeNotExceeded(metadata string) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.metadataSizeNotExceeded(metadata) + }) + return a +} + +// RegistrableBy asserts that an account can be registered by the provided address +func (a *Account) RegistrableBy(addr sdk.AccAddress) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.registrableBy(addr) + }) + return a +} + +// CertificateNotExist asserts the provided certificate +// does not exist in the account already +func (a *Account) CertificateNotExist(cert []byte) *Account { + a.validators = append(a.validators, func(ctrl *Account) error { + return ctrl.certNotExist(cert, nil) + }) + return a +} + // NewController is Account constructor func NewController(ctx sdk.Context, k keeper.Keeper, domain, name string) *Account { return &Account{ @@ -73,13 +224,7 @@ func (a *Account) requireDomain() error { return nil } a.domainCtrl = domain.NewController(a.ctx, a.k, a.domain) - return a.domainCtrl.Validate(domain.MustExist) -} - -// MustExist asserts if an account exists in the state, -// returns an error if it does not. -func MustExist(ctrl *Account) error { - return ctrl.mustExist() + return a.domainCtrl.MustExist().Validate() } // requireAccount finds the accounts and caches it, so future @@ -102,11 +247,6 @@ func (a *Account) mustExist() error { return a.requireAccount() } -// MustNotExist asserts that an account does not exist -func MustNotExist(ctrl *Account) error { - return ctrl.mustNotExist() -} - // mustNotExist is the unexported function executed by MustNotExist func (a *Account) mustNotExist() error { err := a.requireAccount() @@ -116,12 +256,6 @@ func (a *Account) mustNotExist() error { return sdkerrors.Wrapf(types.ErrAccountExists, "account %s already exists in domain %s", a.name, a.domain) } -// ValidAccountName asserts that an account has a valid name based -// on the account regexp saved on the configuration module -func ValidName(ctrl *Account) error { - return ctrl.validName() -} - // requireConfiguration updates the configuration // if it is not already set, and caches it after func (a *Account) requireConfiguration() { @@ -141,12 +275,6 @@ func (a *Account) validName() error { return nil } -// NotExpired asserts that the account has -// not expired compared to the current block time -func NotExpired(ctrl *Account) error { - return ctrl.notExpired() -} - // notExpired is the unexported function used by NotExpired func (a *Account) notExpired() error { if err := a.requireAccount(); err != nil { @@ -169,10 +297,6 @@ func (a *Account) notExpired() error { return sdkerrors.Wrapf(types.ErrAccountExpired, "account %s in domain %s has expired", a.name, a.domain) } -func Renewable(ctrl *Account) error { - return ctrl.renewable() -} - func (a *Account) renewable() error { if err := a.requireAccount(); err != nil { panic("validation check is not allowed on a non existing account") @@ -194,13 +318,6 @@ func (a *Account) renewable() error { return nil } -// Owner asserts the account is owned by the provided address -func Owner(addr sdk.AccAddress) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.ownedBy(addr) - } -} - // ownedBy is the unexported function used by Owner func (a *Account) ownedBy(addr sdk.AccAddress) error { // assert domain exists @@ -215,27 +332,6 @@ func (a *Account) ownedBy(addr sdk.AccAddress) error { return sdkerrors.Wrapf(types.ErrUnauthorized, "%s is not allowed to perform operation in the account owned by %s", addr, a.account.Owner) } -// CertificateExists asserts that the provided certificate -// exists and if it does the index is saved in the provided pointer -// if certIndex pointer is nil the certificate index will not be saved -func CertificateExists(cert []byte, certIndex *int) ControllerFunc { - return func(ctrl *Account) error { - err := ctrl.certNotExist(cert, certIndex) - if err == nil { - return sdkerrors.Wrapf(types.ErrCertificateDoesNotExist, "%x", cert) - } - return nil - } -} - -// CertificateNotExist asserts the provided certificate -// does not exist in the account already -func CertificateNotExist(cert []byte) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.certNotExist(cert, nil) - } -} - // certNotExist is the unexported function used by CertificateNotExist // and CertificateExists, it saves the index of the found certificate // in indexPointer if it is not nil @@ -256,12 +352,6 @@ func (a *Account) certNotExist(newCert []byte, indexPointer *int) error { return nil } -func CertificateSizeNotExceeded(cert []byte) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.certSizeNotExceeded(cert) - } -} - func (a *Account) certSizeNotExceeded(newCert []byte) error { // assert domain exists if err := a.requireAccount(); err != nil { @@ -274,10 +364,6 @@ func (a *Account) certSizeNotExceeded(newCert []byte) error { return nil } -func CertificateLimitNotExceeded(ctrl *Account) error { - return ctrl.certLimitNotExceeded() -} - func (a *Account) certLimitNotExceeded() error { // assert domain exists if err := a.requireAccount(); err != nil { @@ -290,23 +376,6 @@ func (a *Account) certLimitNotExceeded() error { return nil } -// Validate verifies the account against the order of provided controllers -func (a *Account) Validate(checks ...ControllerFunc) error { - for _, check := range checks { - if err := check(a); err != nil { - return err - } - } - return nil -} - -// DeletableBy checks if the account can be deleted by the provided address -func DeletableBy(addr sdk.AccAddress) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.deletableBy(addr) - } -} - func (a *Account) deletableBy(addr sdk.AccAddress) error { if err := a.requireDomain(); err != nil { panic("validation check on a non existing domain is not allowed") @@ -318,7 +387,10 @@ func (a *Account) deletableBy(addr sdk.AccAddress) error { } switch d.Type { case types.ClosedDomain: - if err := a.domainCtrl.Validate(domain.Admin(addr), domain.NotExpired); err != nil { + if err := a.domainCtrl. + Admin(addr). + NotExpired(). + Validate(); err != nil { return err } case types.OpenDomain: @@ -331,13 +403,6 @@ func (a *Account) deletableBy(addr sdk.AccAddress) error { return nil } -// ValidResources verifies that the provided resources are valid for the account -func ValidResources(resources []types.Resource) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.validResources(resources) - } -} - // validResources validates different resources func (a *Account) validResources(resources []types.Resource) error { a.requireConfiguration() @@ -365,13 +430,6 @@ func (a *Account) validResources(resources []types.Resource) error { return nil } -// TransferableBy checks if the account can be transferred by the provided address -func TransferableBy(addr sdk.AccAddress) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.transferableBy(addr) - } -} - func (a *Account) transferableBy(addr sdk.AccAddress) error { if err := a.requireDomain(); err != nil { panic("validation check not allowed on a non existing domain") @@ -380,7 +438,9 @@ func (a *Account) transferableBy(addr sdk.AccAddress) error { switch a.domainCtrl.Domain().Type { // if it has a super user then only domain admin can transfer accounts case types.ClosedDomain: - if a.domainCtrl.Validate(domain.Admin(addr)) != nil { + if a.domainCtrl. + Admin(addr). + Validate() != nil { return sdkerrors.Wrapf(types.ErrUnauthorized, "only domain admin %s is allowed to transfer accounts", a.domainCtrl.Domain().Admin) } // if it has not a super user then only account owner can transfer the account @@ -392,13 +452,6 @@ func (a *Account) transferableBy(addr sdk.AccAddress) error { return nil } -// ResettableBy checks if the account attributes resettable by the provided address -func ResettableBy(addr sdk.AccAddress, reset bool) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.resettableBy(addr, reset) - } -} - func (a *Account) resettableBy(addr sdk.AccAddress, reset bool) error { if err := a.requireDomain(); err != nil { panic("validation check not allowed on a non existing domain") @@ -437,13 +490,6 @@ func (a *Account) gracePeriodFinished() error { return sdkerrors.Wrapf(types.ErrAccountGracePeriodNotFinished, "account %s grace period has not finished", *a.account.Name) } -// ResettableBy checks if the account attributes resettable by the provided address -func ResourceLimitNotExceeded(resources []types.Resource) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.resourceLimitNotExceeded(resources) - } -} - func (a *Account) resourceLimitNotExceeded(resources []types.Resource) error { if err := a.requireAccount(); err != nil { panic("validation check is not allowed on a non existing account") @@ -455,12 +501,6 @@ func (a *Account) resourceLimitNotExceeded(resources []types.Resource) error { return nil } -func MetadataSizeNotExceeded(metadata string) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.metadataSizeNotExceeded(metadata) - } -} - func (a *Account) metadataSizeNotExceeded(metadata string) error { // assert domain exists if err := a.requireAccount(); err != nil { @@ -473,13 +513,6 @@ func (a *Account) metadataSizeNotExceeded(metadata string) error { return nil } -// RegistrableBy asserts that an account can be registered by the provided address -func RegistrableBy(addr sdk.AccAddress) ControllerFunc { - return func(ctrl *Account) error { - return ctrl.registrableBy(addr) - } -} - func (a *Account) registrableBy(addr sdk.AccAddress) error { if err := a.requireDomain(); err != nil { panic("validation check is not allowed on a non existing domain") @@ -488,7 +521,9 @@ func (a *Account) registrableBy(addr sdk.AccAddress) error { switch a.domainCtrl.Domain().Type { // if domain is closed then the registerer must be domain owner case types.ClosedDomain: - return a.domainCtrl.Validate(domain.Admin(addr)) + return a.domainCtrl. + Admin(addr). + Validate() default: return nil } diff --git a/x/starname/controllers/account/account_test.go b/x/starname/controllers/account/account_test.go index 15ad6fa6..4b094100 100644 --- a/x/starname/controllers/account/account_test.go +++ b/x/starname/controllers/account/account_test.go @@ -49,25 +49,27 @@ func TestAccount_transferable(t *testing.T) { t.Run("closed domain", func(t *testing.T) { acc := NewController(ctx, k, "closed", "test") // test success - err := acc.Validate(TransferableBy(keeper.AliceKey)) + err := acc. + TransferableBy(keeper.AliceKey). + Validate() if err != nil { t.Fatalf("got error: %s", err) } // test failure - err = acc.Validate(TransferableBy(keeper.BobKey)) + err = acc.TransferableBy(keeper.BobKey).Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } }) t.Run("open domain", func(t *testing.T) { acc := NewController(ctx, k, "open", "test") - err := acc.Validate(TransferableBy(keeper.BobKey)) + err := acc.TransferableBy(keeper.BobKey).Validate() // test success if err != nil { t.Fatalf("got error: %s", err) } // test failure - err = acc.Validate(TransferableBy(keeper.AliceKey)) + err = acc.TransferableBy(keeper.AliceKey).Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } @@ -100,13 +102,13 @@ func TestAccount_Renewable(t *testing.T) { t.Run("open domain", func(t *testing.T) { // 7(time) + 2(AccountRCM) * 10(AccountRP) = 27 maxValidUntil acc := NewController(ctx.WithBlockTime(time.Unix(7, 0)), k, "open", "test") - err := acc.Validate(Renewable) + err := acc.Renewable().Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } // 100(time) + 2(AccountRCM) * 10(AccountRP) = 120 maxValidUntil acc = NewController(ctx.WithBlockTime(time.Unix(100, 0)), k, "open", "test") - if err := acc.Validate(Renewable); err != nil { + if err := acc.Renewable().Validate(); err != nil { t.Fatalf("got error: %s", err) } }) @@ -125,14 +127,14 @@ func TestAccount_existence(t *testing.T) { // run MustExist test t.Run("must exist success", func(t *testing.T) { acc := NewController(ctx, k, "test", "test") - err := acc.Validate(MustExist) + err := acc.MustExist().Validate() if err != nil { t.Errorf("got error: %s", err) } }) t.Run("must exist fail", func(t *testing.T) { acc := NewController(ctx, k, "test", "does not exist") - err := acc.Validate(MustExist) + err := acc.MustExist().Validate() if !errors.Is(err, types.ErrAccountDoesNotExist) { t.Fatalf("want: %s, got: %s", types.ErrAccountDoesNotExist, err) } @@ -140,14 +142,14 @@ func TestAccount_existence(t *testing.T) { // run MustNotExist test t.Run("must not exist success", func(t *testing.T) { acc := NewController(ctx, k, "test", "does not exist") - err := acc.Validate(MustNotExist) + err := acc.MustNotExist().Validate() if err != nil { t.Errorf("got error: %s", err) } }) t.Run("must not exist fail", func(t *testing.T) { acc := NewController(ctx, k, "test", "test") - err := acc.Validate(MustNotExist) + err := acc.MustNotExist().Validate() if !errors.Is(err, types.ErrAccountExists) { t.Fatalf("want: %s, got: %s", types.ErrAccountExists, err) } @@ -187,7 +189,7 @@ func TestAccount_certNotExist(t *testing.T) { Certificates: []types.Certificate{[]byte("test-cert")}, }, } - err := acc.Validate(CertificateNotExist([]byte("does not exist"))) + err := acc.CertificateNotExist([]byte("does not exist")).Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -199,7 +201,7 @@ func TestAccount_certNotExist(t *testing.T) { }, } i := new(int) - err := acc.Validate(CertificateExists([]byte("exists"), i)) + err := acc.CertificateExists([]byte("exists"), i).Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -223,7 +225,7 @@ func TestAccount_notExpired(t *testing.T) { }, ctx: sdk.Context{}.WithBlockTime(time.Unix(0, 0)), }).WithDomainController(openDomain) - err := acc.Validate(NotExpired) + err := acc.NotExpired().Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -235,7 +237,7 @@ func TestAccount_notExpired(t *testing.T) { }, ctx: sdk.Context{}.WithBlockTime(time.Unix(11, 0)), }).WithDomainController(openDomain) - err := acc.Validate(NotExpired) + err := acc.NotExpired().Validate() if !errors.Is(err, types.ErrAccountExpired) { t.Fatalf("want error: %s, got: %s", types.ErrAccountExpired, err) } @@ -247,7 +249,7 @@ func TestAccount_notExpired(t *testing.T) { }, ctx: sdk.Context{}.WithBlockTime(time.Unix(20, 0)), }).WithDomainController(closedDomain) - err := acc.Validate(NotExpired) + err := acc.NotExpired().Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -260,7 +262,7 @@ func TestAccount_ownedBy(t *testing.T) { acc := &Account{ account: &types.Account{Owner: alice}, } - err := acc.Validate(Owner(alice)) + err := acc.OwnedBy(alice).Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -270,7 +272,7 @@ func TestAccount_ownedBy(t *testing.T) { acc := &Account{ account: &types.Account{Owner: alice}, } - err := acc.Validate(Owner(bob)) + err := acc.OwnedBy(bob).Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("unexpected error: %s, wanted: %s", err, types.ErrUnauthorized) } @@ -283,7 +285,7 @@ func TestAccount_validName(t *testing.T) { account: &types.Account{Name: utils.StrPtr("valid")}, conf: &configuration.Config{ValidAccountName: "^(.*?)?"}, } - err := acc.Validate(ValidName) + err := acc.ValidName().Validate() if err != nil { t.Fatalf("got error: %s", err) } @@ -293,7 +295,7 @@ func TestAccount_validName(t *testing.T) { name: "not valid", conf: &configuration.Config{ValidAccountName: "$^"}, } - err := acc.Validate(ValidName) + err := acc.ValidName().Validate() if !errors.Is(err, types.ErrInvalidAccountName) { t.Fatalf("unexpected error: %s, wanted: %s", err, types.ErrInvalidAccountName) } @@ -310,21 +312,21 @@ func TestAccountRegistrableBy(t *testing.T) { }) t.Run("success in closed domain", func(t *testing.T) { acc := (&Account{}).WithDomainController(closedDomain) - err := acc.Validate(RegistrableBy(keeper.AliceKey)) + err := acc.RegistrableBy(keeper.AliceKey).Validate() if err != nil { t.Fatalf("got error: %s", err) } }) t.Run("fail in closed domain", func(t *testing.T) { acc := (&Account{}).WithDomainController(closedDomain) - err := acc.Validate(RegistrableBy(keeper.BobKey)) + err := acc.RegistrableBy(keeper.BobKey).Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } }) t.Run("success other domain type", func(t *testing.T) { acc := (&Account{}).WithDomainController(openDomain) - err := acc.Validate(RegistrableBy(keeper.AliceKey)) + err := acc.RegistrableBy(keeper.AliceKey).Validate() if err != nil { t.Fatalf("got error: %s", err) } diff --git a/x/starname/controllers/domain/domain.go b/x/starname/controllers/domain/domain.go index d9973272..3620dc39 100644 --- a/x/starname/controllers/domain/domain.go +++ b/x/starname/controllers/domain/domain.go @@ -16,11 +16,9 @@ import ( // ControllerFunc is the function signature for domain validation functions type ControllerFunc func(controller *Domain) error -// ControllerCond is the function signature for domain condition functions -type ControllerCond func(controller *Domain) bool - // Domain is the domain controller type Domain struct { + validators []ControllerFunc domainName string ctx sdk.Context domain *types.Domain @@ -58,8 +56,8 @@ func (c *Domain) WithDomain(dom types.Domain) *Domain { // ---------------------- VALIDATION ----------------------------- // Validate validates a domain based on the provided checks -func (c *Domain) Validate(checks ...ControllerFunc) error { - for _, check := range checks { +func (c *Domain) Validate() error { + for _, check := range c.validators { if err := check(c); err != nil { return err } @@ -67,14 +65,73 @@ func (c *Domain) Validate(checks ...ControllerFunc) error { return nil } -// Condition asserts if the given condition is true -func (c *Domain) Condition(cond ControllerFunc) bool { - return cond(c) == nil +func (c *Domain) Admin(addr sdk.AccAddress) *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.isAdmin(addr) + }) + return c +} + +func (c *Domain) NotExpired() *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.notExpired() + }) + return c +} + +// Superuser makes sure the domain superuser is set to the provided condition +func (c *Domain) Type(Type types.DomainType) *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.dType(Type) + }) + return c +} + +// MustExist checks if the provided domain exists +func (c *Domain) MustExist() *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.mustExist() + }) + return c +} + +// MustNotExist checks if the provided domain does not exist +func (c *Domain) MustNotExist() *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.mustNotExist() + }) + return c } -// Expired checks if the provided domain has expired or not -func Expired(controller *Domain) error { - return controller.expired() +// ValidAccountName checks if the name of the domain is valid +func (c *Domain) ValidName() *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.validName() + }) + return c +} + +// Deletable checks if the domain can be deleted by the provided address +func (c *Domain) DeletableBy(addr sdk.AccAddress) *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.deletableBy(addr) + }) + return c +} + +func (c *Domain) Transferable(flag types.TransferFlag) *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.transferable(flag) + }) + return c +} + +// Renewable checks if the domain is allowed to be renewed +func (c *Domain) Renewable() *Domain { + c.validators = append(c.validators, func(controller *Domain) error { + return controller.renewable() + }) + return c } // expired returns nil if domain expired, otherwise ErrDomainNotExpired @@ -92,10 +149,6 @@ func (c *Domain) expired() error { return sdkerrors.Wrapf(types.ErrDomainNotExpired, "domain %s has not expired", c.domain.Name) } -func GracePeriodFinished(controller *Domain) error { - return controller.gracePeriodFinished() -} - // gracePeriodFinished is the condition that checks if given domain's grace period has finished func (c *Domain) gracePeriodFinished() error { // require configuration @@ -113,12 +166,6 @@ func (c *Domain) gracePeriodFinished() error { return sdkerrors.Wrapf(types.ErrDomainGracePeriodNotFinished, "domain %s grace period has not finished", c.domain.Name) } -func Admin(addr sdk.AccAddress) ControllerFunc { - return func(controller *Domain) error { - return controller.isAdmin(addr) - } -} - // isAdmin makes sure the domain is owned by the provided address func (c *Domain) isAdmin(addr sdk.AccAddress) error { // assert domain exists @@ -132,10 +179,6 @@ func (c *Domain) isAdmin(addr sdk.AccAddress) error { return sdkerrors.Wrapf(types.ErrUnauthorized, "%s is not allowed to perform an operation in a domain owned by %s", addr, c.domain.Admin) } -func NotExpired(controller *Domain) error { - return controller.notExpired() -} - func (c *Domain) notExpired() error { // assert domain exists if err := c.requireDomain(); err != nil { @@ -151,13 +194,6 @@ func (c *Domain) notExpired() error { return sdkerrors.Wrapf(types.ErrDomainExpired, "%s has expired", c.domainName) } -// Superuser makes sure the domain superuser is set to the provided condition -func Type(Type types.DomainType) ControllerFunc { - return func(controller *Domain) error { - return controller.dType(Type) - } -} - func (c *Domain) dType(Type types.DomainType) error { // assert domain exists if err := c.requireDomain(); err != nil { @@ -169,11 +205,6 @@ func (c *Domain) dType(Type types.DomainType) error { return nil } -// MustExist checks if the provided domain exists -func MustExist(controller *Domain) error { - return controller.mustExist() -} - // requireDomain tries to find the domain by name // if it is not found then an error is returned func (c *Domain) requireDomain() error { @@ -194,11 +225,6 @@ func (c *Domain) mustExist() error { return c.requireDomain() } -// MustNotExist checks if the provided domain does not exist -func MustNotExist(controller *Domain) error { - return controller.mustNotExist() -} - // mustNotExist asserts that a domain does not exist func (c *Domain) mustNotExist() error { err := c.requireDomain() @@ -208,11 +234,6 @@ func (c *Domain) mustNotExist() error { return nil } -// ValidAccountName checks if the name of the domain is valid -func ValidName(controller *Domain) error { - return controller.validName() -} - // validName checks if the name of the domain is valid func (c *Domain) validName() error { // require configuration @@ -237,13 +258,6 @@ func (c *Domain) requireConfiguration() { c.conf = &conf } -// Deletable checks if the domain can be deleted by the provided address -func DeletableBy(addr sdk.AccAddress) ControllerFunc { - return func(controller *Domain) error { - return controller.deletableBy(addr) - } -} - // deletableBy is the underlying operation used by DeletableBy controller func (c *Domain) deletableBy(addr sdk.AccAddress) error { if err := c.requireDomain(); err != nil { @@ -265,12 +279,6 @@ func (c *Domain) deletableBy(addr sdk.AccAddress) error { return nil } -func Transferable(flag types.TransferFlag) ControllerFunc { - return func(controller *Domain) error { - return controller.transferable(flag) - } -} - func (c *Domain) transferable(flag types.TransferFlag) error { if err := c.requireDomain(); err != nil { panic("validation check not allowed on a non existing domain") @@ -286,11 +294,6 @@ func (c *Domain) transferable(flag types.TransferFlag) error { } } -// Renewable checks if the domain is allowed to be renewed -func Renewable(ctrl *Domain) error { - return ctrl.renewable() -} - func (c *Domain) renewable() error { c.requireConfiguration() if err := c.requireDomain(); err != nil { diff --git a/x/starname/controllers/domain/domain_test.go b/x/starname/controllers/domain/domain_test.go index 31958455..0048b75a 100644 --- a/x/starname/controllers/domain/domain_test.go +++ b/x/starname/controllers/domain/domain_test.go @@ -345,7 +345,7 @@ func TestDomain_Renewable(t *testing.T) { // 120(DomainValidUntil) + 10(DomainRP) = 130 newValidUntil t.Run("beyond grace period", func(t *testing.T) { d := NewController(ctx.WithBlockTime(time.Unix(241, 0)), k, "deadline-exceeded") - err := d.Validate(Renewable) + err := d.Renewable().Validate() if !errors.Is(err, types.ErrRenewalDeadlineExceeded) { t.Fatalf("want: %s, got: %s", types.ErrRenewalDeadlineExceeded, err) } @@ -355,13 +355,13 @@ func TestDomain_Renewable(t *testing.T) { t.Run("open domain", func(t *testing.T) { // 7(time) + 2(DomainRCM) * 10(DomainRP) = 27 maxValidUntil d := NewController(ctx.WithBlockTime(time.Unix(7, 0)), k, "open") - err := d.Validate(Renewable) + err := d.Renewable().Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } // 100(time) + 2(DomainRCM) * 10(DomainRP) = 120 maxValidUntil d = NewController(ctx.WithBlockTime(time.Unix(100, 0)), k, "open") - if err := d.Validate(Renewable); err != nil { + if err := d.Renewable().Validate(); err != nil { t.Fatalf("got error: %s", err) } }) @@ -369,13 +369,13 @@ func TestDomain_Renewable(t *testing.T) { t.Run("closed domain", func(t *testing.T) { // 7(time) + 2(DomainRCM) * 10(DomainRP) = 27 maxValidUntil d := NewController(ctx.WithBlockTime(time.Unix(7, 0)), k, "closed") - err := d.Validate(Renewable) + err := d.Renewable().Validate() if !errors.Is(err, types.ErrUnauthorized) { t.Fatalf("want: %s, got: %s", types.ErrUnauthorized, err) } // 100(time) + 2(DomainRCM) * 10(DomainRP) = 120 maxValidUntil d = NewController(ctx.WithBlockTime(time.Unix(100, 0)), k, "closed") - if err := d.Validate(Renewable); err != nil { + if err := d.Renewable().Validate(); err != nil { t.Fatalf("got error: %s", err) } }) diff --git a/x/starname/domain_handlers.go b/x/starname/domain_handlers.go index 06ceef00..c5b34960 100644 --- a/x/starname/domain_handlers.go +++ b/x/starname/domain_handlers.go @@ -12,13 +12,16 @@ import ( ) func handlerMsgDeleteDomain(ctx sdk.Context, k keeper.Keeper, msg *types.MsgDeleteDomain) (*sdk.Result, error) { - c := domain.NewController(ctx, k, msg.Domain) + ctrl := domain.NewController(ctx, k, msg.Domain) // do precondition and authorization checks - if err := c.Validate(domain.MustExist, domain.DeletableBy(msg.Owner)); err != nil { + if err := ctrl. + MustExist(). + DeletableBy(msg.Owner). + Validate(); err != nil { return nil, err } // operation is allowed - feeCtrl := fees.NewController(ctx, k, c.Domain()) + feeCtrl := fees.NewController(ctx, k, ctrl.Domain()) fee := feeCtrl.GetFee(msg) // collect fees err := k.CollectFees(ctx, msg, fee) @@ -26,15 +29,18 @@ func handlerMsgDeleteDomain(ctx sdk.Context, k keeper.Keeper, msg *types.MsgDele return nil, sdkerrors.Wrap(err, "unable to collect fees") } // all checks passed delete domain - executor.NewDomain(ctx, k, c.Domain()).Delete() + executor.NewDomain(ctx, k, ctrl.Domain()).Delete() // success TODO maybe emit event? return &sdk.Result{}, nil } // handleMsgRegisterDomain handles the domain registration process func handleMsgRegisterDomain(ctx sdk.Context, k Keeper, msg *types.MsgRegisterDomain) (resp *sdk.Result, err error) { - c := domain.NewController(ctx, k, msg.Name) - err = c.Validate(domain.MustNotExist, domain.ValidName) + ctrl := domain.NewController(ctx, k, msg.Name) + err = ctrl. + MustNotExist(). + ValidName(). + Validate() if err != nil { return nil, err } @@ -61,12 +67,15 @@ func handleMsgRegisterDomain(ctx sdk.Context, k Keeper, msg *types.MsgRegisterDo // handlerMsgRenewDomain renews a domain func handlerMsgRenewDomain(ctx sdk.Context, k keeper.Keeper, msg *types.MsgRenewDomain) (*sdk.Result, error) { - c := domain.NewController(ctx, k, msg.Domain) - err := c.Validate(domain.MustExist, domain.Renewable) + ctrl := domain.NewController(ctx, k, msg.Domain) + err := ctrl. + MustExist(). + Renewable(). + Validate() if err != nil { return nil, err } - feeCtrl := fees.NewController(ctx, k, c.Domain()) + feeCtrl := fees.NewController(ctx, k, ctrl.Domain()) fee := feeCtrl.GetFee(msg) // collect fees err = k.CollectFees(ctx, msg, fee) @@ -74,19 +83,19 @@ func handlerMsgRenewDomain(ctx sdk.Context, k keeper.Keeper, msg *types.MsgRenew return nil, sdkerrors.Wrap(err, "unable to collect fees") } // update domain - executor.NewDomain(ctx, k, c.Domain()).Renew() + executor.NewDomain(ctx, k, ctrl.Domain()).Renew() // success TODO emit event return &sdk.Result{}, nil } func handlerMsgTransferDomain(ctx sdk.Context, k keeper.Keeper, msg *types.MsgTransferDomain) (*sdk.Result, error) { c := domain.NewController(ctx, k, msg.Domain) - err := c.Validate( - domain.MustExist, - domain.Admin(msg.Owner), - domain.NotExpired, - domain.Transferable(msg.TransferFlag), - ) + err := c. + MustExist(). + Admin(msg.Owner). + NotExpired(). + Transferable(msg.TransferFlag). + Validate() if err != nil { return nil, err } diff --git a/x/starname/keeper/executor/account_test.go b/x/starname/keeper/executor/account_test.go new file mode 100644 index 00000000..ce757dc6 --- /dev/null +++ b/x/starname/keeper/executor/account_test.go @@ -0,0 +1,137 @@ +package executor + +import ( + "github.com/iov-one/iovns/x/starname/keeper" + "github.com/iov-one/iovns/x/starname/types" + "reflect" + "testing" +) + +func TestAccount_AddCertificate(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + cert := []byte("a-cert") + ex := NewAccount(testCtx, testKeeper, testAccount) + ex.AddCertificate(cert) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if !reflect.DeepEqual(got.Certificates, append(testAccount.Certificates, cert)) { + t.Fatal("unexpected result") + } +} + +func TestAccount_Create(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + acc := testAccount + acc.Domain = "some-random-domain" + ex := NewAccount(testCtx, testKeeper, acc) + ex.Create() + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(acc.PrimaryKey(), got) + if !reflect.DeepEqual(*got, acc) { + t.Fatal("unexpected result") + } +} + +func TestAccount_DeleteCertificate(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + ex := NewAccount(testCtx, testKeeper, testAccount) + ex.DeleteCertificate(0) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if len(got.Certificates) != 0 { + t.Fatal("unexpected result") + } +} + +func TestAccount_Renew(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + NewAccount(testCtx, testKeeper, testAccount).Renew() + newAcc := new(types.Account) + ok := testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), newAcc) + if !ok { + t.Fatal("account was deleted") + } + if newAcc.ValidUntil != testAccount.ValidUntil+int64(testConfig.AccountRenewalPeriod.Seconds()) { + t.Fatal("time mismatch") + } +} + +func TestAccount_ReplaceResources(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + newRes := []types.Resource{{ + URI: "uri", + Resource: "res", + }} + ex := NewAccount(testCtx, testKeeper, testAccount) + ex.ReplaceResources(newRes) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if !reflect.DeepEqual(got.Resources, newRes) { + t.Fatal("unexpected result") + } + +} + +func TestAccount_State(t *testing.T) { + +} + +func TestAccount_Transfer(t *testing.T) { + ex := NewAccount(testCtx, testKeeper, testAccount) + t.Run("no-reset", func(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + + ex.Transfer(keeper.CharlieKey, false) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if !got.Owner.Equals(keeper.CharlieKey) { + t.Fatal("unexpected owner") + } + if !reflect.DeepEqual(got.Resources, testAccount.Resources) { + t.Fatal("unexpected resources") + } + if !reflect.DeepEqual(got.MetadataURI, testAccount.MetadataURI) { + t.Fatal("unexpected metadata") + } + if !reflect.DeepEqual(got.Certificates, testAccount.Certificates) { + t.Fatal("unexpected certs") + } + }) + t.Run("with-reset", func(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + + ex.Transfer(keeper.BobKey, true) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if !got.Owner.Equals(keeper.BobKey) { + t.Fatal("owner mismatch") + } + if got.MetadataURI != "" || got.Resources != nil || got.Certificates != nil { + t.Fatal("reset not performed") + } + }) +} + +func TestAccount_UpdateMetadata(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + + newMeta := "a new meta" + ex := NewAccount(testCtx, testKeeper, testAccount) + ex.UpdateMetadata(newMeta) + got := new(types.Account) + testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if !reflect.DeepEqual(got.MetadataURI, newMeta) { + t.Fatal("unexpected result") + } +} + +func TestAccount_Delete(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + ex := NewAccount(testCtx, testKeeper, testAccount) + ex.Delete() + got := new(types.Account) + found := testKeeper.AccountStore(testCtx).Read(testAccount.PrimaryKey(), got) + if found { + t.Fatal("account was not deleted") + } +} diff --git a/x/starname/keeper/executor/domain_test.go b/x/starname/keeper/executor/domain_test.go index 44557aae..f7757156 100644 --- a/x/starname/keeper/executor/domain_test.go +++ b/x/starname/keeper/executor/domain_test.go @@ -123,3 +123,44 @@ func TestDomain_Transfer(t *testing.T) { } }) } + +func TestDomain_Renew(t *testing.T) { + t.Run("success renew from config", func(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + ex := NewDomain(testCtx, testKeeper, testDomain) + ex.Renew() + newDom := new(types.Domain) + ok := testKeeper.DomainStore(testCtx).Read(testDomain.PrimaryKey(), newDom) + if !ok { + t.Fatal("domain does not exist anymore") + } + if newDom.ValidUntil != testDomain.ValidUntil+int64(testConfig.DomainRenewalPeriod.Seconds()) { + t.Fatal("mismatched times") + } + }) + t.Run("success renew from account", func(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + var accValidUntil int64 = 10000 + ex := NewDomain(testCtx, testKeeper, testDomain) + ex.Renew(accValidUntil) + newDom := new(types.Domain) + ok := testKeeper.DomainStore(testCtx).Read(testDomain.PrimaryKey(), newDom) + if !ok { + t.Fatal("domain does not exist anymore") + } + if newDom.ValidUntil != accValidUntil { + t.Fatal("mismatched times") + } + }) +} + +func TestDomain_Delete(t *testing.T) { + t.Run("success", func(t *testing.T) { + testCtx, _ := testCtx.CacheContext() + NewDomain(testCtx, testKeeper, testDomain).Delete() + ok := testKeeper.DomainStore(testCtx).Read(testDomain.PrimaryKey(), &types.Domain{}) + if ok { + t.Fatal("domain was not deleted") + } + }) +} diff --git a/x/starname/keeper/executor/main_test.go b/x/starname/keeper/executor/main_test.go index 7186dd28..9f9ef8d4 100644 --- a/x/starname/keeper/executor/main_test.go +++ b/x/starname/keeper/executor/main_test.go @@ -5,7 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/iov-one/iovns/mock" "github.com/iov-one/iovns/pkg/utils" + "github.com/iov-one/iovns/x/configuration" + "github.com/iov-one/iovns/x/starname/keeper" + "github.com/iov-one/iovns/x/starname/types" tmtypes "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" db "github.com/tendermint/tm-db" @@ -17,14 +21,42 @@ import ( var testCtx sdk.Context var testKey = sdk.NewKVStoreKey("test") var testCdc *codec.Codec +var _, testAddrs = utils.GeneratePrivKeyAddressPairs(2) +var aliceKey sdk.AccAddress = testAddrs[0] +var bobKey sdk.AccAddress = testAddrs[1] +var testConfig = &configuration.Config{ + Configurer: nil, + DomainRenewalPeriod: 10 * time.Second, + AccountRenewalPeriod: 20 * time.Second, +} + +var testKeeper keeper.Keeper +var testAccount = types.Account{ + Domain: "a-super-domain", + Name: utils.StrPtr("a-super-account"), + Owner: aliceKey, + ValidUntil: 10000, + Resources: []types.Resource{ + { + URI: "a-super-uri", + Resource: "a-super-res", + }, + }, + Certificates: []types.Certificate{types.Certificate("a-random-cert")}, + Broker: nil, + MetadataURI: "metadata", +} -var aliceKey sdk.AccAddress -var bobKey sdk.AccAddress +var testDomain = types.Domain{ + Name: "a-super-domain", + Admin: bobKey, + ValidUntil: 100, + Type: types.ClosedDomain, +} func newTest() error { - _, addr := utils.GeneratePrivKeyAddressPairs(2) - aliceKey = addr[0] - bobKey = addr[1] + mockConfig := mock.NewConfiguration(nil, testConfig) + // gen test store testCdc = codec.New() mdb := db.NewMemDB() ms := store.NewCommitMultiStore(mdb) @@ -34,6 +66,9 @@ func newTest() error { return err } testCtx = sdk.NewContext(ms, tmtypes.Header{Time: time.Now()}, true, log.NewNopLogger()) + testKeeper = keeper.NewKeeper(testCdc, testKey, mockConfig, nil, nil) + testKeeper.AccountStore(testCtx).Create(&testAccount) + testKeeper.DomainStore(testCtx).Create(&testDomain) return nil }