Search code examples
grailsgrails-orm

Testing Grails controllers that use @CurrentTenant


Given a controller such as this with a simple GORM query:

@CurrentTenant
class FooController {
    def list() {
        [foo: Foo.list()]
    }
}

And a Spock test such as this:

class FooControllerSpec
    extends HibernateSpec
    implements ControllerUnitTest<FooController>, DataTest {

    Tenant tenant

    void setupSpec() {
        mockDomains Foo, Tenant
    }

    @Override
    Map getConfiguration() {
        [(Settings.SETTING_MULTI_TENANT_RESOLVER_CLASS):  SystemPropertyTenantResolver]
    }

    def setup() {
        tenant = new Tenant(name: "test").save(flush:true)
        System.setProperty(SystemPropertyTenantResolver.PROPERTY_NAME, tenant.id.toString())
        controller.transactionManager = transactionManager // For HibernateSpec in a controller
    }

    void "list"() {
        when:
        controller.list()

        then:
        response.status == 200
    }
}

I would expect to be able to unit test controllers that use the @CurrentTentant annotation.

Functionally this does work, it will only show Foo's for the current tenant, but in the unit test I get an exception:

org.grails.datastore.mapping.model.DatastoreConfigurationException: Current datastore [org.grails.datastore.mapping.simple.SimpleMapDatastore@370c9018] is not configured for Multi-Tenancy

    at org.grails.datastore.gorm.services.DefaultTenantService.withCurrent(DefaultTenantService.groovy:74)
    at com.foo.web.FooControllerSpec.show with no id(FooControllerSpec.groovy:39)

Is there a way to setup the current datastore for Multi-Tenancy in a unit test with a controller.

I tried to emulate the setup from this guide, but they are using @CurrentTenant on a GORM data service http://guides.grails.org/discriminator-per-tenant/guide/index.html


Solution

Part of the solution was to only use HibernateSpec, however I also had to configure the datasource as so to get the dataSource to be MultiTenant aware in my spec:

@Override
Map getConfiguration() {
    [(Settings.SETTING_MULTI_TENANT_RESOLVER_CLASS): SystemPropertyLongTenantResolver,
     (Settings.SETTING_MULTI_TENANCY_MODE): 'DISCRIMINATOR',
     (org.grails.orm.hibernate.cfg.Settings.SETTING_DB_CREATE): "create-drop"]
}

And since our the SystemPropertyTenantResolver can only set/get a String I had to implement my own for the test that would return a Long.


Solution

  • Don't implement DataTest and change:

    void setupSpec() {
        mockDomains Foo, Tenant
    }
    

    to

    List<Class> getDomainClasses() { [Foo, Tenant] }