MongoDB plugin - how to make it to not create a datasource during testing?

时间:2015-07-08 15:46:25

标签: mongodb hibernate grails

I'm working on in a project using Grails 2.3.8 and MongoDB. In my project I've included MongoDB GORM plugin along with hibernate to simplify the DB connection stuff:

BuildConfig.groovy

// default config stuff here

grails.project.dependency.resolution = {
   ...

   plugins {
       ...
       compile ":mongodb:3.0.3"
       runtime ":hibernate:3.6.10.4"
    }
}

DataSource.groovy

environments {

    development {
        grails {
            mongo {
                host = "localhost"
                port = 27017
                databaseName = "myDB"
                // runs without --auth option needs no authentication
            }
        }
    }

    production {
        grails {
            mongo {
                databaseName = "myDB"
                username = "user"
                password = "*****"
                replicaSet = [
                        "master-host:port",
                        "slave1-host:port",
                        "slave2-host:port"
                ]
            }
        }
    }
}

This works just fine if I run my app on my local machine (development) or pre-prod servers.

My problem is I've created an integration test for my controller in which the service is mocked and there's no need to establish a database connection at all. When I run the test like this:

grails test test-app --debug-fork --stacktrace --verbose -integration

The environment is properly set to "test" but I'm getting this exception:

Error Fatal error running tests: Error creating bean with name 'mongoTransactionManager': Cannot resolve reference to bean 'mongoDatastore' while setting bean property 'datastore'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoDatastore': FactoryBean threw exception on object creation; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms; nested exception is com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoTransactionManager': Cannot resolve reference to bean 'mongoDatastore' while setting bean property 'datastore'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoDatastore': FactoryBean threw exception on object creation; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms; nested exception is com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:336)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1456)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
    at org.codehaus.groovy.grails.commons.spring.ReloadAwareAutowireCapableBeanFactory.doCreateBean(ReloadAwareAutowireCapableBeanFactory.java:123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.codehaus.groovy.grails.transaction.ChainedTransactionManagerPostProcessor.registerAdditionalTransactionManagers(ChainedTransactionManagerPostProcessor.java:114)
    at org.codehaus.groovy.grails.transaction.ChainedTransactionManagerPostProcessor.postProcessBeanFactory(ChainedTransactionManagerPostProcessor.java:101)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:694)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:633)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461)
    at org.codehaus.groovy.grails.commons.spring.DefaultRuntimeSpringConfiguration.getApplicationContext(DefaultRuntimeSpringConfiguration.java:156)
    at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:169)
    at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:127)
    at org.codehaus.groovy.grails.project.loader.GrailsProjectLoader$_configureApplication_closure3.doCall(GrailsProjectLoader.groovy:134)
    at org.codehaus.groovy.grails.project.loader.GrailsProjectLoader$_configureApplication_closure3.doCall(GrailsProjectLoader.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1254)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1086)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:910)
    at groovy.lang.Closure.call(Closure.java:411)
    at groovy.lang.Closure.call(Closure.java:405)
    at org.codehaus.groovy.grails.cli.api.BaseSettingsApi.profile(BaseSettingsApi.java:342)
    at org.codehaus.groovy.grails.project.loader.GrailsProjectLoader.configureApplication(GrailsProjectLoader.groovy:131)
    at org.codehaus.groovy.grails.test.runner.phase.IntegrationTestPhaseConfigurer.prepare(IntegrationTestPhaseConfigurer.groovy:59)
    at org.codehaus.groovy.grails.test.runner.phase.TestPhaseConfigurer$prepare.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:89)
    at org.codehaus.groovy.grails.test.runner.GrailsProjectTestRunner$_runAllTests_closure7.doCall(GrailsProjectTestRunner.groovy:311)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1254)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1086)
    at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:1110)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:910)
    at groovy.lang.Closure.call(Closure.java:411)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.callClosureForMapEntry(DefaultGroovyMethods.java:3873)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:1354)
    at org.codehaus.groovy.runtime.dgm$149.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.grails.test.runner.GrailsProjectTestRunner.runAllTests(GrailsProjectTestRunner.groovy:301)
    at org.codehaus.groovy.grails.test.runner.GrailsProjectTestRunner.runAllTests(GrailsProjectTestRunner.groovy:216)
    at org.codehaus.groovy.grails.test.runner.GrailsProjectTestRunner.runAllTests(GrailsProjectTestRunner.groovy)
    at org.codehaus.groovy.grails.test.runner.GrailsProjectTestRunner$runAllTests$0.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at org.codehaus.groovy.grails.cli.fork.testing.ForkedGrailsTestRunner.runInstance(ForkedGrailsTestRunner.groovy:128)
    at org.codehaus.groovy.grails.cli.fork.ForkedGrailsProjectClassExecutor.run(ForkedGrailsProjectClassExecutor.groovy:74)
    at org.codehaus.groovy.grails.cli.fork.testing.ForkedGrailsTestRunner.main(ForkedGrailsTestRunner.groovy:75)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoDatastore': FactoryBean threw exception on object creation; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms; nested exception is com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:151)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:103)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1514)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
    ... 70 more
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms; nested exception is com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
    at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:69)
    at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:1829)
    at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:393)
    at org.grails.datastore.mapping.mongo.MongoDatastore.initializeIndices(MongoDatastore.java:285)
    at org.grails.datastore.mapping.mongo.MongoDatastore.createMongoTemplate(MongoDatastore.java:276)
    at org.grails.datastore.mapping.mongo.MongoDatastore.afterPropertiesSet(MongoDatastore.java:221)
    at org.springframework.beans.factory.InitializingBean$afterPropertiesSet.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
    at org.grails.datastore.gorm.mongo.bean.factory.MongoDatastoreFactoryBean.getObject(MongoDatastoreFactoryBean.groovy:54)
    at org.grails.datastore.gorm.mongo.bean.factory.MongoDatastoreFactoryBean.getObject(MongoDatastoreFactoryBean.groovy)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:144)
    ... 75 more
Caused by: com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms
    at com.mongodb.BaseCluster.getServer(BaseCluster.java:87)
    at com.mongodb.DBTCPConnector.getServer(DBTCPConnector.java:654)
    at com.mongodb.DBTCPConnector.access$300(DBTCPConnector.java:39)
    at com.mongodb.DBTCPConnector$MyPort.getConnection(DBTCPConnector.java:503)
    at com.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:451)
    at com.mongodb.DBTCPConnector.getPrimaryPort(DBTCPConnector.java:409)
    at com.mongodb.DBCollectionImpl.createIndex(DBCollectionImpl.java:339)
    at com.mongodb.DBCollection.createIndex(DBCollection.java:564)
    at com.mongodb.DBCollection.ensureIndex(DBCollection.java:663)
    at com.mongodb.DBCollection.ensureIndex(DBCollection.java:603)
    at org.grails.datastore.mapping.mongo.MongoDatastore$6.doInDB(MongoDatastore.java:341)
    at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:391)
    ... 85 more

Based on this portion of the stacktrace:

nested exception is com.mongodb.MongoTimeoutException: Timed out while waiting for a server that matches AnyServerSelector{} after 10000 ms

It seems to me the plugin is trying to connect to a mongo instance regardless the environment is "test". It makes sense because if I start a local mongo in my computer the test runs successfuly.

I've spent a day and a half googling for this issue but the common reply is "your mongo instance isn't running". I realised that but for the test I actually don't need it.

For a little more context, this test must run in a Jenkins server which doesn't have any mongo instance running and throws the very same exception as expected.

Any help on this is really appreciated.

1 个答案:

答案 0 :(得分:2)

集成测试针对“完全烘焙”的grails应用程序运行 - 如果你在dev和prod中使用数据库,那么你将需要一个测试。

此外,如果你真的在做自动化测试部分,你需要一个测试数据库用于其他测试,所以现在就创建一个。即使该测试不使用它,它也构成您正在测试的“完整grails环境”的一部分。

在Jenkins作业中,您可以传递环境设置以指示测试环境使用指定的配置文件作为数据源。我使用test / conf / app-config.groovy中存储的特定于测试的app-config.groovy文件来完成此操作。该配置指向Jenkins服务器可以看到的长期AWS RDS实例(数据库不在Jenkins服务器上)。 Jenkins构建步骤基本上调用:

grails test-app -Dapp.config.location = test / conf / app-config.groovy integration:

(我在工作中面临同样的问题,只是为所有三种环境创建MySQL数据库,开发,生产和测试。并且可以做更多,因为我们在客户选择H2,MSSQL,Oracle或者MySQL的)。