Saving an object from Grails controller fails - grails

There is a controller just updating an object:
def obj = Table.find(...)
obj.state = "END"
if(!obj.save(flush:true)) ...
// Session flushing does not help too.
// I am able to fetch that object again here but it is never persisted to DB
When deployed onto a Debian, the object is not actually persisted although there is no any errors reported (nor by manual checking nor by failOnError). But if deployed onto my local Windows machine the object is persisted correctly. The both machines are connected to the same DB.
Moving the save into a service or covering it withTransaction are workarounds. Yes, I know services are a better place to deal with DB. Instead I'm interesting to find what is the cause of such inconsistent and problematic behavior (and how to fix it in a single place). Or it is prohibited by design doing such things in controllers?
Grails 2.1.1, Tomcat
Excerptions from DataSource.groovy:
dataSource {
driverClassName = "oracle.jdbc.driver.OracleDriver"
dialect = org.hibernate.dialect.Oracle10gDialect
pooled = true
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = false
cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
}

Please check if there is no validation errors.
obj.validate()
obj.errors.each {
if(obj.hasErrors)
println it
}

Related

grails 2.4.4 integration test not using the test datasource

Help!
Our plugin project integration tests should hit the database specified in the datasource.groovy, but for some reason they ignore it, and do it in memory.
Its a plugin which provides the core services (i.e. DB access) to several grails apps which are each a grails application.
Datasource.groovy looks like this:
dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
}
environments {
development {
dataSource {
dbCreate = "create-drop"
url = "jdbc:mysql://127.0.0.1:3306/db"
username = "someuser"
password = "somepass"
}
}
test {
dataSource {
dbCreate = "update"
url = "jdbc:mysql://127.0.0.1:3306/db"
username = "someuser"
password = "somepass"
}
}
production {
dataSource {
}
}
}
The test (SiteIntegrationSpec.goovy)
import grails.test.mixin.TestFor
import grails.test.spock.IntegrationSpec
#TestFor(Site)
class SiteIntegrationSpec extends IntegrationSpec {
static transactional = false
def setup() {
}
def cleanup() {
}
void "test something"() {
when:
Site site
site = new Site(name: "asdf", description: "asdfsd").save(failOnError: true)
then:
site.id == 3
when:
Site site2 = Site.get(1L)
then:
site2.name == "root"
}
}
Data already existing in the site table:
ID name description
1 root root
2 test test
The first test should insert a record which will happen to have an ID of 3. It actually inserts with an ID of 1, i.e. its not seeing or hitting the test database, its using some mock or internal db which is not defined anywhere.
The second test fails as instead of retrieving "root" it retrieves "asdf"
What I have tried:
creating a separate DB for test. Didn't help.
specifying -Dgrails.env=test when running tests. Didn't help
running the tests with the DB down. This correctly fails with cant create pool type exception.
changing the test datasource password to an incorrect one - this correctly throws an exception.
grails -Dgrails.env=test test-app com.me.myproject.SiteIntegrationSpec --stacktrace --verbose
So grails is connecting to the test datasource, but then the integration tests are not using it!
Any ideas?
Edit: Site is a domain object:
class Site {
String name
String description
}
Plugin DataSource.groovy files aren't included in the plugin zip, and if you somehow manually or programmatically include them, they'll be ignored. The same goes for Config.groovy, UrlMappings.groovy, and BootStrap.groovy. In general when something is usable from a plugin, if the application has a file with the same name and location, it overrides the plugin's file, so that would keep this from working also.
You could define a dataSource bean in your plugin's doWithSpring that replaces the one Grails creates based on DataSource.groovy that uses values from a file that exists in the plugin zip, or that is located in the application if that makes sense. Note that there are really 3 DataSource beans and two of them are proxies of the "real" one, so you need to define yours as dataSourceUnproxied so the other two proxy yours and retain the behavior that they add.
Another thing that you will need to fix once you resolve this is your use of unit test annotations in an integration test. Never use Mock, TestFor, or any unit test mixin annotation or base class, since their purpose is to establish a fairly realistic environment that makes up for Spring, Hibernate, installed plugins, and lots of Grails functionality not being available, but in an integration test they are available, and the unit test stuff will stomp on the real instances.
Also - why are you using static transactional = false? This disables an important integration test feature where all of your test methods run in a transaction that is rolled back at the end of the tests pass or fail. This ensures that nothing you do in a test influences other tests - everything is independent. If you disable this, you need to undo all of the changes, and it's easy to miss some and introduce false negatives or worse - false positives - into your tests.

Tables not being created for quartz plugin with Grails 2.3.11

I'm trying to enable job persistence using the quartz plugin for grails (http://grails.org/plugin/quartz) but everytime I try to create a new job it cannot find the table. It looks like the plugin isn't creating the tables.
The database I'm using in mysql and my grails version is 2.3.11. I've tried to mirror the configuration used in this blog (http://blog.robinpercy.com/2012/11/06/grails-clustered-quartz-configs-by-environment/) but the tables aren't being created.
Here is my quartz configuration :
jdbcProps = {
scheduler.instanceName = "quartz"
scheduler.instanceId = "AUTO"
threadPool.class = "org.quartz.simpl.SimpleThreadPool"
threadPool.threadCount = 3
threadPool.threadPriority = 5
jobStore.misfireThreshold = 60000
jobStore.class = "org.quartz.impl.jdbcjobstore.JobStoreTX"
jobStore.driverDelegateClass = "org.quartz.impl.jdbcjobstore.MSSQLDelegate"
jobStore.useProperties = false
jobStore.tablePrefix = "qrtz_"
jobStore.isClustered = true
jobStore.clusterCheckinInterval = 5000
plugin.shutdownhook.class = "org.quartz.plugins.management.ShutdownHookPlugin"
plugin.shutdownhook.cleanShutdown = true
}
environments {
development {
quartz {
autoStartup = true
jdbcStore = true
waitForJobsToCompleteOnShutdown = true
props(jdbcProps)
}
}
}
Quartz can find the database specified in my datasource.groovy file but it cannot find the tables it needs.
dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
username = "root"
password = "root"
dbCreate = "create-drop" // one of 'create', 'create-drop','update'
url = "jdbc:mysql://localhost:3306/appDatabase?autoReconnect=true"
properties {
numTestsPerEvictionRun=3
testOnBorrow=true
testWhileIdle=true
testOnReturn=true
validationQuery="SELECT 1"
}
}
Here is the exception
An error occurred while scanning for the next triggers to fire.
org.quartz.JobPersistenceException: Couldn't acquire next trigger: Table 'appDatabase.qrtz_TRIGGERS' doesn't exist [See nested exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'appDatabase.qrtz_TRIGGERS' doesn't exist
Am I missing something here? Do I need to manually create the tables or do I have some configuration error?
I haven't used this in a while, but I doubt it will create tables for you. The Quartz distro comes with DDL for over 20 databases in the docs/dbTables directory, so you would use the file for your database and version, and customize as needed before running them.
I did a conference talk a few years ago that included clustering Quartz and included an automated way to use Hibernate cfg.xml and hbm.xml files to create the tables. You can download the sample app and use that same approach - it'll still work with Hibernate 3 and should with Hibernate 4, but might require an update to the <!DOCTYPE ...> in the xml.

Liquibase contexts with Grails

I am having a problem getting Liquibase changeset contexts to play nicely within my Grails application. I have a set of changesets that I would like to only run within a "test" context. However, they are executing every time. I think I have a configuration problem.
The Liquibase documentation states that you just have to add the context="test" attribute to your changeSet. For my proof of concept test I am going to create an insert of a Patient record that I want to insert on Test, but not in my local Development environment. My changeset has the context added:
<changeSet id="v1.1-garbage-1" author="Eric" context="test">
<insert tableName="patient">
[...]
</insert>
</changeSet>
And then within my DataSource.groovy file I define my environments:
environments {
development {
dataSource {
dbCreate = "create"
jndiName = "java:comp/env/jdbc/mydatabasename"
}
}
test {
dataSource {
dbCreate = "create"
url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000"
}
}
[...]
So I have two environments, development and test. Then in my Config.groovy, I set up the Grails databasemigration plugin to only have the context "development" (for this proof of concept):
// Database Migration plugin
grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ['changelog.xml']
grails.plugin.databasemigration.autoMigrateScripts = ['RunApp', 'TestApp']
grails.plugin.databasemigration.changelogFileName = "changelog.xml"
grails.plugin.databasemigration.development.updateOnStartContexts = ['development']
In that final line, as I understand it, I am telling the databasemigration plugin to set the "development" contexts to 'development', thus when Liquibase executes, it should not run my changeset above, because it is defined within the 'test' context.
Yet when I run the application, my changeset is executed. What have I bungled or missed in the setup?
My bet is that the last config line is not doing what you expect.
According to the "Multiple DataSource Example" section at http://grails-plugins.github.io/grails-database-migration/docs/manual/guide/3%20Configuration.html this syntax is used for multiple data sources. So, in your case the updateOnStartContexts parameter is going to be applied to a datasource named dataSource_development which you obviously don't have...
Can you try instead the following:
environments {
development{
grails.plugin.databasemigration.updateOnStartContexts = ['development']
}
}

Grails Data Migration Rollback

Hi I'm trying something very simple with Grails domain class. I am adding to my class a field and I want to use data migration plugin to rollback once so that the field I added gets removed.
First I created the initial change log as followed:
grails dbm-generate-changelog changelog.groovy
Then I added the following to the Config.groovy file:
grails.plugin.databasemigration.updateOnStart = true
grails.plugin.databasemigration.updateOnStartFileNames = ['changelog.groovy']
Then I added an extra field to my domain class and performed the following:
grails dbm-gorm-diff added-new-field.groovy --add
I ran the app (grails run-app), after which I perform a:
grails dbm-rollback-count 1
After which I run the app again using: grails run-app
but the field is still there.
I am using MySQL for db. Here's how I have it configured in DataSource.groovy:
dataSource {
pooled = true
driverClassName = "com.mysql.jdbc.Driver"
dialect = "org.hibernate.dialect.MySQL5InnoDBDialect"
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = false
cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
}
// environment specific settings
environments {
development {
dataSource {
dbCreate = 'update'
url = "jdbc:mysql://localhost/dashboard?useUnicode=yes&characterEncoding=UTF-8"
username ="foo"
password = "bar"
}
}
..... and on.....
Can someone guide me to how the rollback is performed?
I am using:
Grails 2.2.2
database-migration:1.3.2
When grails dbm-rollback-count 1 is performed It makes changes only to the database using the groovy changelog filed by taking the very last change set in the log and undoing that. If you run your app again the following lines in Groovy.config will put those fields back into the tables:
grails.plugin.databasemigration.updateOnStart = true grails.plugin.databasemigration.updateOnStartFileNames = ['changelog.groovy']
I'm not really sure what purpose dbm-rollback-count servers in my case but that it what it did.
I was thinking that performing a rollback will not only remove the last changeset (added field) in the database but also remove that field variable from the domain class as well.

Grails Connections behaving very differently in Integration test

We have a custom data source that extends BasicDataSource. We have overridden the getConnection method which does a couple things inside of it. When we run the webapp outside of testing, when we call a service from a controller it will grab a new connection and use that connection until the service is done. All is well. However, inside an integration test, the connection appears to be grabbed before the test even calls the controller. Flow below
Regular Run:
call controller -> controller calls service method -> connection is grabbed -> service method is run and returns to controller
Integration Test:
connection is grabbed -> call controller from test -> controller calls service method -> service method is run and returns to controller
Needless to say, this is giving us problems as having the correct connection is very important for our app. Thoughts?
Edit: Still getting significant issues with this. We've reached a point where we have to avoid creating integration tests, or do some manual connection switching (which defeats half the point of the tests)
DataSource.groovy
dataSource {
pooled = true
dialect="org.hibernate.dialect.OracleDialect"
properties {
maxActive = 50
maxIdle = 10
initialSize = 10
minEvictableIdleTimeMillis = 1800000
timeBetweenEvictionRunsMillis = 1800000
maxWait = 10000
testWhileIdle = true
numTestsPerEvictionRun = 3
testOnBorrow = true
}
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = true
cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
}
This is not a final Answer, however I believe this is an explanation of what is going on:
Running as Web app: your Service class has a transactionManager which has a sessionFactory, which gets the connection! So in this case, assuming that you Service is 'transactional=true' all methods that you call in your services will have a 'Session.beginTransaction()' in the beginning of the method(there is a Grails`s Proxy to do that, when you set 'transactional=true'), which will call all that stack until getConnection().
Running as Integration Test: as Grails doesnt commit your DB changes, it always rollback them! I believe that when you are starting your Integration test, grails is creating a transaction right away! so it will be able to rollback it afterwards!(which make totally sense right!), you can confirm that taking a look at the class org.codehaus.groovy.grails.test.support.GrailsTestInterceptor. The method init() is called before your services in your integration test. So that`s why getConnection() is being called before everything!
Suggestion:
You can try setting your integration test class as 'transaction=false' and see if getConnection() doesn't get call in the beginning!
Go to Transactions section in here to see more!
Just dont forget that in your test you will have to rollback your transaction! if your set transaction=false.

Resources