Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

class Authority is not a domain class or GORM has not been initialized correctly or has already been shutdown

I'm working on a grails rest app. The grails version I'm using is 3.3.1. I'm using spring-security-rest for authorization. I've created the following classes using the s2-quickstart command.

  1. User
  2. Authority
  3. UserAuthority

The app runs fine but the unit tests for the User class fail with the following error in console.

java.lang.IllegalStateException: Either class [hungr.Authority] is not a domain class or GORM has not been initialized correctly or has already been shutdown. Ensure GORM is loaded and configured correctly before calling any methods on a GORM entity.
at org.grails.datastore.gorm.GormEnhancer.stateException(GormEnhancer.groovy:469)
at org.grails.datastore.gorm.GormEnhancer.findStaticApi(GormEnhancer.groovy:300)
at org.grails.datastore.gorm.GormEnhancer.findStaticApi(GormEnhancer.groovy:296)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.currentGormStaticApi(GormEntity.groovy:1349)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.staticMethodMissing(GormEntity.groovy:756)
at hungr.UserController.$tt__save(UserController.groovy:39)
at hungr.UserController.save_closure1(UserController.groovy)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:430)
at grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:94)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:91)
at org.grails.testing.runtime.support.ActionSettingMethodHandler.invoke(ActionSettingMethodHandler.groovy:28)
at hungr.UserControllerSpec.Test the save action correctly persists(UserControllerSpec.groovy:90)

I've tried referring to the answer at GORM fails to realize Domain classes from a plugin are GORM classes but nothing worked. I'm pretty new to grails hence I have no clue what may be going wrong. the classes I'm using are:

User.Groovy

@GrailsCompileStatic
@EqualsAndHashCode(includes='username')
@ToString(includes='username', includeNames=true, includePackage=false)
class User implements Serializable, UserDetails {

private static final long serialVersionUID = 1
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
String name
String email
Integer age
Boolean isVeg
byte[] profilePicture
String profilePictureContentType
String facebookId
String facebookProfilePictureUrl
boolean  isFacebookUser
static hasMany = [notifications: Notification, posts: DiaryItem, comments: Comment]
Set<Authority> getAuthorities() {
    (UserAuthority.findAllByUser(this) as List<UserAuthority>)*.authority as Set<Authority>
}

@Override
boolean isAccountNonExpired() {
    return !accountExpired
}

@Override
boolean isAccountNonLocked() {
    return !accountLocked
}

@Override
boolean isCredentialsNonExpired() {
    return !passwordExpired
}

static constraints = {
    password nullable: false, blank: false, password: true
    username nullable: false, blank: false, unique: true
    facebookId nullable: true
    name nullable: false, blank: false, maxSize: 100
    email blank: false, email: true
    age nullable: false, min: 8
    isVeg nullable: false
    profilePicture nullable: true, maxSize: 1073741824
    profilePictureContentType nullable: true
    isFacebookUser nullable: false
    facebookProfilePictureUrl nullable: true, maxSize: 1000
}

static mapping = {
    password column: '`password`'
}
}

Authority.Groovy

@GrailsCompileStatic
@EqualsAndHashCode(includes='authority')
@ToString(includes='authority', includeNames=true, includePackage=false)
class Authority implements Serializable, GrantedAuthority {

    private static final long serialVersionUID = 1

    String authority

    static constraints = {
    authority nullable: false, blank: false, unique: true
    }

    static mapping = {
    cache true
    }
}

UserAuthority.Groovy

@GrailsCompileStatic
@ToString(cache=true, includeNames=true, includePackage=false)
class UserAuthority implements Serializable {

private static final long serialVersionUID = 1

User user
Authority authority

@Override
boolean equals(other) {
    if (other instanceof UserAuthority) {
        other.userId == user?.id && other.authorityId == authority?.id
    }
}

@Override
int hashCode() {
    int hashCode = HashCodeHelper.initHash()
    if (user) {
        hashCode = HashCodeHelper.updateHash(hashCode, user.id)
    }
    if (authority) {
        hashCode = HashCodeHelper.updateHash(hashCode, authority.id)
    }
    hashCode
}

static UserAuthority get(long userId, long authorityId) {
    criteriaFor(userId, authorityId).get()
}

static boolean exists(long userId, long authorityId) {
    criteriaFor(userId, authorityId).count()
}

private static DetachedCriteria criteriaFor(long userId, long authorityId) {
    UserAuthority.where {
        user == User.load(userId) &&
        authority == Authority.load(authorityId)
    }
}

static UserAuthority create(User user, Authority authority, boolean flush = false) {
    def instance = new UserAuthority(user: user, authority: authority)
    instance.save(flush: flush)
    instance
}

static boolean remove(User u, Authority r) {
    if (u != null && r != null) {
        UserAuthority.where { user == u && authority == r }.deleteAll()
    }
}

static int removeAll(User u) {
    u == null ? 0 : UserAuthority.where { user == u }.deleteAll() as int
}

static int removeAll(Authority r) {
    r == null ? 0 : UserAuthority.where { authority == r }.deleteAll() as int
}

static constraints = {
    user nullable: false
    authority nullable: false, validator: { Authority r, UserAuthority ur ->
        if (ur.user?.id) {
            if (UserAuthority.exists(ur.user.id, r.id)) {
                return ['userRole.exists']
            }
        }
    }
}

static mapping = {
    id composite: ['user', 'authority']
    version false
}
}

EDIT 1: The Unit Test class is:

class UserControllerSpec extends Specification implements          
ControllerUnitTest<UserController>, DomainUnitTest<User> {

def populateValidParams(params) {
    assert params != null

    // TODO: Populate valid properties like...
    //params["name"] = 'someValidName'
    params["username"]
    params["password"]
    params["name"] = "User"
    params["email"] = "[email protected]"
    params["age"] = 19
    params["isVeg"] = false
     //       new MockMultipartFile('profilePicture', 'myImage.jpg', imgContentType, imgContentBytes)

   // def multipartFile = new GrailsMockMultipartFile('profilePicture', 'profilePicture.jpg', 'image/jpeg', new byte[0])
    //request.addFile(multipartFile)
  //  params["profilePicture"] =// new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', "1234567" as byte[])
    params["profilePictureContentType"] = "image/jpeg"
    params["facebookId"] = "fb_id"
    params["facebookProfilePictureUrl"] = "http://abc.def"
    params["isFacebookUser"] = true
    //assert false, "TODO: Provide a populateValidParams() implementation for this generated test suite"
}

void "Test the index action returns the correct model"() {
    given:
    controller.userService = Mock(UserService) {
        1 * list(_) >> []
        1 * count() >> 0
    }

    when:"The index action is executed"
    controller.index()

    then:"The model is correct"
    !model.userList
    model.userCount == 0
}

void "Test the create action returns the correct model"() {
    when:"The create action is executed"
    controller.create()

    then:"The model is correctly created"
    model.user!= null
}

void "Test the save action with a null instance"() {
    when:"Save is called for a domain instance that doesn't exist"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'POST'
    request.format = 'form'
    controller.save(null)

    then:"A 404 error is returned"
    response.redirectedUrl == '/user/index'
    flash.message != null
}

void "Test the save action correctly persists"() {
    given:
    controller.userService = Mock(UserService) {
        1 * save(_ as User)
    }

    when:"The save action is executed with a valid instance"
    response.reset()
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'POST'
    request.format = 'form'
    byte[] b = new byte[1]
    b[0]= 123
    request.addFile(new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', b))
    populateValidParams(params)
    def user = new User(params)
    user.id = 1

    controller.save(user)

    then:"A redirect is issued to the show action"
    response.redirectedUrl == '/user/show/1'
    controller.flash.message != null
}

void "Test the save action with an invalid instance"() {
    given:
    controller.userService = Mock(UserService) {
        1 * save(_ as User) >> { User user ->
            throw new ValidationException("Invalid instance", user.errors)
        }
    }

    when:"The save action is executed with an invalid instance"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'POST'
    def user = new User()
    controller.save(user)

    then:"The create view is rendered again with the correct model"
    model.user != null
    view == 'create'
}

void "Test the show action with a null id"() {
    given:
    controller.userService = Mock(UserService) {
        1 * get(null) >> null
    }

    when:"The show action is executed with a null domain"
    controller.show(null)

    then:"A 404 error is returned"
    response.status == 404
}

void "Test the show action with a valid id"() {
    given:
    controller.userService = Mock(UserService) {
        1 * get(2) >> new User()
    }

    when:"A domain instance is passed to the show action"
    controller.show(2)

    then:"A model is populated containing the domain instance"
    model.user instanceof User
}

void "Test the edit action with a null id"() {
    given:
    controller.userService = Mock(UserService) {
        1 * get(null) >> null
    }

    when:"The show action is executed with a null domain"
    controller.edit(null)

    then:"A 404 error is returned"
    response.status == 404
}

void "Test the edit action with a valid id"() {
    given:
    controller.userService = Mock(UserService) {
        1 * get(2) >> new User()
    }

    when:"A domain instance is passed to the show action"
    controller.edit(2)

    then:"A model is populated containing the domain instance"
    model.user instanceof User
}


void "Test the update action with a null instance"() {
    when:"Save is called for a domain instance that doesn't exist"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'PUT'
    controller.update(null)

    then:"A 404 error is returned"
    response.redirectedUrl == '/user/index'
    flash.message != null
}

void "Test the update action correctly persists"() {
    given:
    controller.userService = Mock(UserService) {
        1 * save(_ as User)
    }

    when:"The save action is executed with a valid instance"
    response.reset()
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'PUT'
    request.format = 'form'
    request.addFile(new MockMultipartFile('profilePicture', 'file.jpg', 'image/jpeg', "1234567" as byte[]))
    populateValidParams(params)
    def user = new User(params)
    user.id = 1

    controller.update(user)

    then:"A redirect is issued to the show action"
    response.redirectedUrl == '/user/show/1'
    controller.flash.message != null
}

void "Test the update action with an invalid instance"() {
    given:
    controller.userService = Mock(UserService) {
        1 * save(_ as User) >> { User user ->
            throw new ValidationException("Invalid instance", user.errors)
        }
    }

    when:"The save action is executed with an invalid instance"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'PUT'
    controller.update(new User())

    then:"The edit view is rendered again with the correct model"
    model.user != null
    view == 'edit'
}

void "Test the delete action with a null instance"() {
    when:"The delete action is called for a null instance"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'DELETE'
    controller.delete(null)

    then:"A 404 is returned"
    response.redirectedUrl == '/user/index'
    flash.message != null
}

void "Test the delete action with an instance"() {
    given:
    controller.userService = Mock(UserService) {
        1 * delete(2)
    }

    when:"The domain instance is passed to the delete action"
    request.contentType = FORM_CONTENT_TYPE
    request.method = 'DELETE'
    controller.delete(2)

    then:"The user is redirected to index"
    response.redirectedUrl == '/user/index'
    flash.message != null
}
}
like image 961
Aditya Gurjar Avatar asked Feb 23 '18 06:02

Aditya Gurjar


1 Answers

So normally in a Unit test you test a single unit, User in this case. Because you want to test additional entities, you need to add them to the test. You can do this by implementing getDomainClassesToMock. Best is to use the DataTest trait instead of the DomainUnitTest in this situation (DomainUnitTest extends DataTest).

So your test should look like:

class UserControllerSpec extends Specification implements          
ControllerUnitTest<UserController>, DataTest {

    Class<?>[] getDomainClassesToMock(){
        return [User,Authority,UserAuthority] as Class[]
    }
    .... 
}
like image 98
Dennie de Lange Avatar answered Oct 31 '22 14:10

Dennie de Lange