Grails 2.5.5 w/ Spock Integration tests fail when using addTo*() - grails

This is driving me nuts. 2.4.4 My integration tests all pass. Upgrading to 2.5.5 and I get errors like this all over the place:
No signature of method: Project.addToMonitorings() is applicable for argument types: (Monitoring) values: [Monitoring : (unsaved)] Possible solutions: getMonitorings()
I cannot seem to track down how to update the integration tests to make them pass again.
Example (current) Test:
class MonitoringServiceSpec extends Specification {
def monitoringService
TestDataFactory f // factory that builds objects so we can use them in other tests
def setup() {
f = new TestDataFactory()
}
void "results can be limited"() {
given:
Project p = f.getProject()
p.save(flush: true, failOnError: true)
def params = new EcosListParams(new GrailsParameterMap ([offset: 0, max:1, sortColumn: 'id', order: 'asc'], null))
when:
p.addToMonitorings(f.getMonitoring(p)).save(flush: true, failOnError: true)
p.refresh()
def results = monitoringService.getProjectMonitorings(params, p.id)
then:
results.totalCount == 2
results.size() == 1
}
...
}
I get this error everywhere in my app that have one-to-many relationships. They worked perfectly fine in 2.4.4.

Here is what I had to do to get it to work. The getMonitoring method in the data factory already added the Project to the object. It must implicitly do an addTo
import groovy.sql.Sql;
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsParameterMap
import spock.lang.*
class MonitoringServiceSpec extends Specification {
def f = new TestDataFactory()
def proj
def sql
def dataSource
def monitoringService
def setup() {
sql = new Sql(dataSource);
proj = f.getProject().save()
Monitoring mon1 = f.getMonitoring(proj).save()
Monitoring mon2 = f.getMonitoring(proj).save()
// don't need addTo, the getMonitoring method above implicitly adds it to the project
proj.save(flush: true, failOnError: true).refresh()
}
void "results can be limited"() {
given:
def params = new EcosListParams(new GrailsParameterMap ([offset: 0, max:1, sortColumn: 'id', order: 'asc'], null))
when:
def results = monitoringService.getProjectMonitorings(params, proj.id)
then:
results.totalCount == 2
results.size() == 1
}
void "results can be offset"() {
given:
def params1 = new EcosListParams(new GrailsParameterMap ([offset: 0, max:1, sortColumn: 'id', order: 'asc'], null))
def params2 = new EcosListParams(new GrailsParameterMap ([offset: 1, max:1, sortColumn: 'id', order: 'asc'], null))
when:
def results1 = monitoringService.getProjectMonitorings(params1, proj.id)
def results2 = monitoringService.getProjectMonitorings(params2, proj.id)
then:
results1.size() > 0
results1.id != results2
}
}
TestDataFactory
Monitoring getMonitoring(Project p) {
HabitatObjectiveSuccess hos = HabitatObjectiveSuccess.list(max: 1).get(0);
return new Monitoring(visitDate: new Date(), notes: 'notes', created: new Date(), createdBy: getPerson(),
lastUpdated: new Date(), lastUpdatedBy: getPerson(), maintActivitiesOccurring: 2,
maintActivitiesOccurrText: 'maintActivitiesOccurrText', landownerObjectivesMet: 1,
landownerObjectivesMetText: 'landownerObjectivesMetText', speciesObjectivesMet: 1,
speciesObjectivesMetText: 'speciesObjectivesMetText', habitatObjectiveSuccess: hos,
habitatObjectiveSuccessText: 'habitatObjectiveSuccessText', project: p
)
}

Related

No such DLS method "style" (MarkupBuilder)

I try to build a string in html-format to send it as an E-Mail in a jenkins-pipeline. I have following bit of code:
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def html = new MarkupBuilder( writer )
html.table( class: "squishSummary" ) {
style( type: "text/css" ) {
mkp.yield( getTableStyle() )
}
...
}
def getTableStyle() {
....
}
Unfortunately this runs into an error while executing the pipeline: java.lang.NoSuchMethodError: No such DSL method 'style' found among steps [...] If I'm understanding it correctly the jenkins-server tries to execute the style-command as a jenkins build-step, what reasonably fails. How can I fix this?
the following code works fine:
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def html = new MarkupBuilder( writer )
html.table( class: "squishSummary" ) {
style( type: "text/css" ) {
mkp.yield("123")
}
}
println writer
however if you declare variable named style then you get the error similar to yours
so this code will fail with groovy.lang.MissingMethodException: No signature of method ...
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def html = new MarkupBuilder( writer )
def style = "my style1" //just add this line and code fails
html.table( class: "squishSummary" ) {
style( type: "text/css" ) {
mkp.yield("123")
}
}
println writer
to solve problem use delegate or GString instead of plain method name:
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def html = new MarkupBuilder( writer )
def style = "style1"
html.table( class: "squishSummary" ) {
delegate.style( type: "text/css" ) {
mkp.yield("123")
}
//or like this:
"${'style'}"( type: "text/css" ) {
mkp.yield("123")
}
}
println writer

Grails 2.5.0 - metaParams on Set?

I have the following class:
class User {
...
static hasMany = [data: MyData]
...
}
I would like to get user.data on a User object but filter the returned list using metaParams like in findAllBy (https://grails.github.io/grails-doc/latest/ref/Domain%20Classes/findAllBy.html).
Is this possible?
With a criteria query you can do something like this:
def id = /* some User.id here */
// http://grails.github.io/grails-doc/2.1.0/ref/Domain%20Classes/createCriteria.html
def data = User.createCriteria().list(max: 10, offset: 100) {
projections {
property 'data'
}
eq 'id', id
order 'something', 'desc'
}
If you end up with duplicate MyData instances, try using HQL instead. Like this:
// https://grails.github.io/grails-doc/latest/ref/Domain%20Classes/executeQuery.html
User.executeQuery 'select distinct u.data from User as u where u.id = :id', [id: id, max: 10, offset: 5]

grails with spring security can't with create default user in BootStrap

I'm using Grails with Spring Security plugin and want to create default User when application starts.
I have default User and Authority classes
My BootStrap.groovy is as follows:
class BootStrap {
def init = { servletContext ->
def userAuthority = Authority.findByAuthority('ROLE_USER') ?: new Authority(authority: 'ROLE_USER').save(flush: true)
def adminAuthority = Authority.findByAuthority('ROLE_ADMIN') ?: new Authority(authority: 'ROLE_ADMIN').save(flush: true)
def defaultUser = new User(username: "admin", password: "password", accountExpired: false, accountLocked: false,
passwordExpired: false, enabled: true).save(flush: true)
assert defaultUser != null
if (!defaultUser.getAuthorities().contains(userAuthority)) {
UserAuthority.create defaultUser , userAuthority, true
}
if (!defaultUser.getAuthorities().contains(adminAuthority)) {
UserAuthority.create defaultUser , adminAuthority, true
}
assert User.count() == 1
assert Authority.count() == 2
assert UserAuthority.count() == 2
}
def destroy = {}
}
When I start the application it gives me an exception and fails:
Error initializing the application: Cannot invoke method getAuthorities() on null object
So it doesn't create a User instance for some reason (have no idea why).
I'm using default in memory H2 database.
What it can be? I'll really appreciate any help because I've spent a couple of hours on resolving this :(

Reloading Grails Bootstrap with environments

There is a good answer for reloading the Grails Bootstrap in Reloading bootstrap with Grails
But I have environments defined in my init closure and so I get the error:
groovy.lang.MissingMethodException: No signature of method: BootStrap.environments() is applicable for argument types: (BootStrap$_closure1_closure3) values: [BootStrap$_closure1_closure3#19ad0326]
Bootstrap code is basically the spring-security domain classes for role, user, user_role
import org.mine.*
class BootStrap
{
def init =
{ servletContext ->
environments
{
development
{
def adminRole = new DummyRole(authority: 'ROLE_ADMIN').save(flush: true)
def userRole = new DummyRole(authority: 'ROLE_USER').save(flush: true)
def user = new DummyUser(username: 'user1', email_address: 'user1#mine.org', enabled: true, password: 'password')
def user1 = new DummyUser(username: 'user2', email_address: 'user2#mine.org', enabled: true, password: 'password')
def user2 = new DummyUser(username: 'user3', email_address: 'user3#mine.org', enabled: true, password: 'password')
user.save(flush: true)
user1.save(flush: true)
user2.save(flush: true)
DummyUserDummyRole.create manager, adminRole, true
DummyUserDummyRole.create user, userRole, true
DummyUserDummyRole.create user1, userRole, true
DummyUserDummyRole.create user2, userRole, true
assert DummyUser.count() >= 9
assert DummyRole.count() >= 10
assert DummyUserDummyRole.count() >= 9
} // end-development
test {
// bootstrap data for test environment
}
production {
// bootstrap data for production environment
}
}
}
def destroy =
{
// code here
}
}
This works for me:
def servletCtx = org.codehaus.groovy.grails.web.context.ServletContextHolder.servletContext
def myBootstrapArtefact = grailsApplication.getArtefacts('Bootstrap')[-1]
BootStrap.metaClass.environments = grails.util.Environment.&executeForCurrentEnvironment
myBootstrapArtefact.referenceInstance.init(servletCtx)
Lovingly copied (and then modified) from the answer you referenced :-)
I alway used this solution and it worked for me. Works with Grails 3.x too. Here
It is much easier to just swap your syntax to:
Environment.executeForCurrentEnvironment {
production {
// do something in production
}
development {
// do something only in development
}
}

Reading parameters enterd on the screen

I have a page that accepts parameters from the user. I read this parameter in my action using params.playerId. and then do the computations with it.
I have changed my UI now and am using extJS for display purposes.
Therefore I have an edit and an editData action.
editData action has the code to run the sql and execute the appropriate js file and displays edit.jsp. However, in the editData action, when I use params.playerId, I get a null value.
What can be a work round for this scenario?
My code before integrating with extJS: list action is called and list.gsp is displayed with data.
def list = {
def session = sessionFactory.getCurrentSession()
def result = session.createSQLQuery("select player_id from w.music where player_id=(params.playerId)").list();
def tuneInstanceList = new ArrayList()
def tune = new Tune()
result.each
{
tune.playerId = it
tune.playerPrice = "100" tuneInstanceList.add(tune)
}
[recoveryInstanceList: recoveryInstanceList]
}
Now, when I ntegrate with extJS, I get the value of params.playerId as null. Code is below.
list.gsp:
<%# page import="tune.Music"%>
<script type="text/javascript">
var ds = new Ext.data.Store({
autoLoad: true,
proxy: new Ext.data.HttpProxy({
url: 'http://localhost:8080/tune/music/listData'}),
reader: new Ext.data.JsonReader({
results: 'total',
root:'items',
id:'id'
},
[
{name: 'playerId'},
{name: 'playerPrice'}
]
)
});
var cm = new Ext.grid.ColumnModel([
{header: "Player Id", width: 70, sortable:true, dataIndex: 'playerId'},
{header: "Player Price", width: 90, dataIndex: 'playerPrice'}
]);
//cm.defaultSortable = true;
// create the grid
var grid = new Ext.grid.GridPanel({
ds: ds,
cm: cm,
renderTo:'grid-example',
width:1300,
height:300
});
</script>
<div class="body">
<!--<g:javascript library="examples"/>-->
<!-- EXAMPLES -->
<h1>Ext Grid</h1>
<div id="grid-example"></div>
</div>
My controller action:
def list={ }
def listData = {
def session = sessionFactory.getCurrentSession()
def result = session.createSQLQuery("select player_id from w.music where player_id= (params.playerId)").list();
def tuneInstanceList = new ArrayList()
result.each {
def tune = new Tune()
tune.playerId = it tune.playerPrice = "100"
tuneInstanceList.add(tune)
}
def listResult = [total: tunInstanceList.size(), items: tunInstanceList]
render listResult as JSON;
}
How can I retrieve the parameters that have been entered by the user??
Thanks!
Worked around this issue by reading the parameters in list() action and saving it in a session.
Then used this session data in the listData() action to do the computations.
Not sure if this is the best approach. This is just a workaround.

Resources