Liquibase contexts with Grails - 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']
}
}

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.

Reusing Grails variables inside Config.groovy

In my Config.groovy I have:
// Lots of other stuff up here...
environments {
development {
myapp.port = 7500
}
production {
myapp.port = 7600
}
}
fizz {
buzz {
foo = "Port #${myapp.port}"
}
}
When I run my app via grails -Dgrails.env=development run-app, my web app spins up without errors, but then at runtime I see that the value of fizz.buzz.foo is "Port #[:]". I would expect it to be "Port #7500".
Why isn't Grails seeing my var?
You could probably get away with this if myapp.port were not in an environments block but that's a side effect of the way Config.groovy is processed rather than being intentional. And if you were to override myapp.port in an external config file then fizz.buzz.foo would still end up with the value from Config.groovy, not the override from the external.
You could make it a late-binding GString using a closure to pull the value from grails.util.Holders.config when fizz.buzz.foo is referenced rather than when it is defined:
foo = "Port #${-> Holders.config.myapp.port}"
This is different from "Port #${Holders.config.myapp.port}" which would attempt to access the config at the point where Config.groovy is being parsed.
If the value you're defining here is one that will ultimately end up defining a property of a Spring bean (for example many of the spring-security-core plugin configuration options become bean properties) then you may be able to do
foo = 'Port #${myapp.port}'
with single rather than double quotes. This causes the resulting config entry to contain the literal string ${myapp.port}, which will be resolved against the config by the Spring property placeholder mechanism when it is used as a bean property value.
Another way is to simply use variables within your config file like this:
def appPort = 7500
environments {
production {
appPort = 7600
myapp.port = appPort
}
}
fizz {
buzz {
foo = "Port #$appPort"
}
}
And also, you don't need to send the -Dgrails.environment=development when you execute the run-app, it's the default one.

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.

Configuration of Grails plugin

I'm developing my first Grails plugin. It has to access a webservice. The Plugin will obviously need the webservice url. What is the best way to configure this without hardcoding it into the Groovy classes? It would be nice with different config for different environments.
You might want to Keep It Simple(tm). You may define the URL directly in Config.groovy -including per-environment settings- and access it from your plugin as needed using grailsApplication.config (in most cases) or a ConfigurationHolder.config object (See further details in the manual).
As an added bonus that setting may also be defined in standard Java property files or on other configuration files specified in grails.config.locations.
e.g. in Config.groovy
// This will be the default value...
myPlugin.url=http://somewhe.re/test/endpoint
environments {
production {
// ...except when running in production mode
myPlugin.url=http://somewhe.re/for-real/endpoint
}
}
later, in a service provided by your plugin
import org.codehaus.groovy.grails.commons.ConfigurationHolder
class MyPluginService {
def url = ConfigurationHolder.config.myPlugin.url
// ...
}
If its only a small (read: one item) config option, it might just be easier to slurp in a properties file. If there are some number of configuration options, and some of them should be dynamic, i would suggest doing what the Acegi Security plugin does - add a file to /grails-app/conf/plugin_name_config.groovy perhaps.
added bonus is that the user can execute groovy code to compute their configuration options (much better over using properties files), as well as being able to do different environments with ease.
check out http://groovy.codehaus.org/ConfigSlurper , which is what grails internally use to slurp configs like config.groovy.
//e.g. in /grails-app/conf/MyWebServicePluginConfig.groovy
somePluginName {
production {
property1 = "some string"
}
test {
property1 = "another"
}
}
//in your myWebServicePlugin.groovy file, perhaps in the doWithSpring closure
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().getClassLoader())
ConfigObject config
try {
config = new ConfigSlurper().parse(classLoader.loadClass('MyWebServicePluginConfig'))
} catch (Exception e) {/*??handle or what? use default here?*/}
assert config.test.property1.equals("another") == true

Resources